Differences between notify of and notifyAll of in Java

  • 2021-10-11 18:41:56
  • OfStack

What is the difference between notify () and notifyAll ()?

Explain two concepts first.

Waiting pool: Assuming that a thread A calls the wait () method of an object, the thread A will release the lock of the object and enter the waiting pool of the object, and the threads in the waiting pool will not compete for the lock of the object. Lock pool: The thread can execute the synchronized code of the object only if it acquires the lock of the object. Only one thread can acquire the lock of the object at a time, and other threads can only wait in the lock pool

Then let's talk about the difference between notify and notifyAll

If a thread calls an object's wait () method, the thread is in the object's wait pool, and the threads in the wait pool do not compete for the object's lock. When a thread calls an object's notifyAll () method (waking up all wait threads) or notify () method (waking up only one wait thread at random), the woken thread will enter the object's lock pool, and the threads in the lock pool will compete for the object's lock. That is, after calling notify, only one thread will enter the lock pool from the wait pool, while notifyAll will move all the threads in the wait pool of the object into the lock pool and wait for the lock to compete A high priority thread has a high probability of competing for an object lock. If a thread does not compete for the object lock, it will remain in the lock pool. Only when the thread calls the wait () method again will it return to the wait pool. The thread competing for the object lock continues to execute until the synchronized code block is executed, and it releases the object lock, at which time the threads in the lock pool will continue to compete for the object lock.

To sum up, another explanation for waking up threads can be said to be moving threads from the wait pool to the lock pool. After notifyAll is called, all threads will be moved from the wait pool to the lock pool, and then participate in the lock competition. If the competition is successful, it will continue to execute. If it is unsuccessful, it will stay in the lock pool and wait for the lock to be released before participating in the competition again. notify will only wake up one thread.

With these theoretical foundations, the following example of notify may cause deadlock, but notifyAll does not

Test code


public class TestNotifyNotifyAll {
 
 private static Object obj = new Object();
 
 public static void main(String[] args) {
  
  // Test  RunnableImplA wait()        
  Thread t1 = new Thread(new RunnableImplA(obj));
  Thread t2 = new Thread(new RunnableImplA(obj));
  t1.start();
  t2.start();
  
  //RunnableImplB notify()
  Thread t3 = new Thread(new RunnableImplB(obj));
  t3.start();
  
  
//  //RunnableImplC notifyAll()
//  Thread t4 = new Thread(new RunnableImplC(obj));
//  t4.start();
 }
 
}
 
 
class RunnableImplA implements Runnable {
 
 private Object obj;
 
 public RunnableImplA(Object obj) {
  this.obj = obj;
 }
 
 public void run() {
  System.out.println("run on RunnableImplA");
  synchronized (obj) {
   System.out.println("obj to wait on RunnableImplA");
   try {
    obj.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("obj continue to run on RunnableImplA");
  }
 }
}
 
class RunnableImplB implements Runnable {
 
 private Object obj;
 
 public RunnableImplB(Object obj) {
  this.obj = obj;
 }
 
 public void run() {
  System.out.println("run on RunnableImplB");
  System.out.println(" Sleep 3 Seconds ...");
  try {
   Thread.sleep(3000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  synchronized (obj) {
   System.out.println("notify obj on RunnableImplB");
   obj.notify();
  }
 }
}
 
class RunnableImplC implements Runnable {
 
 private Object obj;
 
 public RunnableImplC(Object obj) {
  this.obj = obj;
 }
 
 public void run() {
  System.out.println("run on RunnableImplC");
  System.out.println(" Sleep 3 Seconds ...");
  try {
   Thread.sleep(3000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  synchronized (obj) {
   System.out.println("notifyAll obj on RunnableImplC");
   obj.notifyAll();
  }
 }
}

Result: obj. notify () is called only once, and one of the threads t1 or t2 is always waiting to be awakened, and the program does not terminate

run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplB
Sleep for 3 seconds...
notify obj on RunnableImplB
obj continue to run on RunnableImplA

Note out t3 and start the t4 thread. Call the obj. notifyAll () method


public class TestNotifyNotifyAll { 
 private static Object obj = new Object();
  public static void main(String[] args) {
  
  // Test  RunnableImplA wait()        
  Thread t1 = new Thread(new RunnableImplA(obj));
  Thread t2 = new Thread(new RunnableImplA(obj));
  t1.start();
  t2.start();
  
//  //RunnableImplB notify()
//  Thread t3 = new Thread(new RunnableImplB(obj));
//  t3.start();
  
  
  //RunnableImplC notifyAll()
  Thread t4 = new Thread(new RunnableImplC(obj));
  t4.start();
 } 
}

Results: t1 and t2 threads can be executed completely

run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplC
Sleep for 3 seconds...
notifyAll obj on RunnableImplC
obj continue to run on RunnableImplA
obj continue to run on RunnableImplA


Related articles: