Java notify() run before wait()?

后端 未结 3 1843
渐次进展
渐次进展 2021-01-05 11:57
public class ThreadA {
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.start();

        synchronized(b){
            try{
          


        
相关标签:
3条回答
  • 2021-01-05 12:18

    You should almost always have a predicate together with wait/notify. That is, you need a condition that you can check, such as a variable becoming true, a queue becoming empty/full etc. Just blindly waiting for someone to call .notify() have very few use cases.

    So, The following is Not OK, for the reason you say, the other thread could call .notify() before ThreadA calls .wait()

    public class ThreadA {
        public static Object latch = new Object();
        public static void main(String[] args) {
            ThreadB b = new ThreadB();
            b.start();
            synchronized(latch ) {
                latch.wait(); //wait for B to finish a calculation
            }
            System.out.println("Total is: " + b.total);
    
        }
    }
    
    class ThreadB extends Thread {
        int total;
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                total += i;
            }
           synchronized(ThreadA.latch) {
               ThreadA.latch.notify();
           }
        }
    }
    

    You need to do something like this:

     public class ThreadA {
        public static Object latch = new Object();
        public static boolean done = false;
        public static void main(String[] args) {
            ThreadB b = new ThreadB();
            b.start();
            synchronized(latch ) {
                while (!done) {   //wait for B to indicate it is finished.
                    latch.wait(); 
                }
            }
            System.out.println("Total is: " + b.total);
    
        }
    }
    
    class ThreadB extends Thread {
        int total;
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                total += i;
            }
           synchronized(ThreadA.latch) {
               ThreadA.done = true;         
               ThreadA.latch.notify();
           }
        }
    }
    

    Note that in the above, the done variable is protected by the synchronized block, .wait() will atomically release/re-aquire that lock. So there is no race condition, and if .notify() is called before we get to the .wait() call , ThreadA will discover that because done will be true and not enter the .wait() call at all.

    For a simple case such as this code, you can just wait for ThreadB to to end, can be done with b.join();

    0 讨论(0)
  • 2021-01-05 12:19

    One of the many possible solutions for your problem is:

    public class ThreadA {
      public static final CyclicBarrier barrier = new CyclicBarrier(2);
    
      public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();
        try {
          barrier.await();
          System.out.println("Total is: " + b.total);
        } catch (InterruptedException | BrokenBarrierException ex) {
        }
      }
    }
    
    class ThreadB extends Thread {
        int total;
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                total += i;
            }
            try {
              ThreadA.barrier.await();
            } catch (InterruptedException | BrokenBarrierException ex) {
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-05 12:29

    I guess you want to do something like this

    public class ThreadA {
        public static void main(String[] args) {
            ThreadB b = new ThreadB();
            b.start();
            b.join(); // Wait for thread b to finish 
    
            System.out.println("Total is: " + b.total);
    
        }
    }
    

    You should also let ThreadB only implement Runnable and not extend Thread.

    class ThreadB implements Runnable {
        int total;
    
        public void run() {
            for (int i = 0; i < 100; i++) {
                total += i;
            } 
        }
    }
    

    and then use it

    ThreadB tb = new ThreadB();
    Thread b = new Thread(tb);
    
    0 讨论(0)
提交回复
热议问题