Usage of notify(), notifyAll(), wait()

Posted by lmg on Mon, 22 Jul 2019 22:46:38 +0200

Original Link: http://www.cnblogs.com/leekenky/p/3649829.html

/**

* Please note the author longdick at http://longdick.iteye.com

*

*/

 

wait(), notify(), and notifyAll() are three methods defined in the Object class that can be used to control the state of threads.

All three methods end up calling jvm-level native methods.As the jvm runs on different platforms, it may be slightly different.

 

  • If the object invokes the wait method, the thread holding the object will hand over control of the object and be in a waiting state.
  • If an object invokes the notify method, it notifies a thread that is waiting for control of the object to continue running.
  • If the object calls the notifyAll method, it will notify all threads waiting for control of the object to continue running.

 

There are three over load methods for the wait method:

wait()

wait(long)

wait(long,int)

The wait method uses parameters to specify the length of time to wait.If no parameters are specified, by default, wait until notified.

 

 

Here is a demonstration code that illustrates complex problems in the most concise way:

Here is a brief description:

NotifyThread is a thread class used to simulate threads that notify other waiting States after 3 seconds;

WaitThread is a thread class used to simulate waiting;

The intermediate object to wait for is flag, a String object;

The main method starts one Notify thread and three wait threads at the same time;

 

 

  1. public class NotifyTest {  
  2.     private  String flag = "true";  
  3.   
  4.     class NotifyThread extends Thread{  
  5.         public NotifyThread(String name) {  
  6.             super(name);  
  7.         }  
  8.         public void run() {       
  9.             try {  
  10.                 sleep(3000);//Delay 3 seconds notification  
  11.             } catch (InterruptedException e) {  
  12.                 e.printStackTrace();  
  13.             }  
  14.               
  15.                 flag = "false";  
  16.                 flag.notify();  
  17.         }  
  18.     };  
  19.   
  20.     class WaitThread extends Thread {  
  21.         public WaitThread(String name) {  
  22.             super(name);  
  23.         }  
  24.   
  25.         public void run() {  
  26.               
  27.                 while (flag!="false") {  
  28.                     System.out.println(getName() + " begin waiting!");  
  29.                     long waitTime = System.currentTimeMillis();  
  30.                     try {  
  31.                         flag.wait();  
  32.                     } catch (InterruptedException e) {  
  33.                         e.printStackTrace();  
  34.                     }  
  35.                     waitTime = System.currentTimeMillis() - waitTime;  
  36.                     System.out.println("wait time :"+waitTime);  
  37.                 }  
  38.                 System.out.println(getName() + " end waiting!");  
  39.               
  40.         }  
  41.     }  
  42.   
  43.     public static void main(String[] args) throws InterruptedException {  
  44.         System.out.println("Main Thread Run!");  
  45.         NotifyTest test = new NotifyTest();  
  46.         NotifyThread notifyThread =test.new NotifyThread("notify01");  
  47.         WaitThread waitThread01 = test.new WaitThread("waiter01");  
  48.         WaitThread waitThread02 = test.new WaitThread("waiter02");  
  49.         WaitThread waitThread03 = test.new WaitThread("waiter03");  
  50.         notifyThread.start();  
  51.         waitThread01.start();  
  52.         waitThread02.start();  
  53.         waitThread03.start();  
  54.     }  
  55.   
  56. }  

 

OK, if you take this program and run it, you'll find it doesn't work at all, what happened?Full screen java.lang.IllegalMonitorStateException.

Yes, there are many problems with this program. Let's look at them one by one.

 

First of all, here are a few facts to note

 

  1. At any one time, the object's control (monitor) can only be owned by one thread.
  2. Whether you execute the wait, notify, or notifyAll method of an object, you must ensure that the currently running thread takes control of the object (monitor)
  3. If the above three methods of the object are executed in a thread without control, a java.lang.IllegalMonitorStateException exception is reported.
  4. JVM is multi-threaded and by default it does not guarantee the sequentiality of the runtime threads

 

Based on these facts, we need to ensure that threads have control of objects.

That is, when executing the wait method in waitThread, make sure that waitThread has control over flag;

When executing the notify method in notifyThread, ensure that notifyThread has control over flag.

 

Threads take control in three ways:

 

  1. Executes a synchronization instance method of the object.
  2. Executes a synchronous static method for the object's corresponding class.
  3. Executes a synchronization block with a synchronization lock on the object.
Let's take a third approach:
Package the above notify and wait methods in the synchronization block
 
  1. synchronized (flag) {  
  2.                 flag = "false";  
  3.                 flag.notify();  
  4.             }  

 

 

  1. synchronized (flag) {  
  2.                 while (flag!="false") {  
  3.                     System.out.println(getName() + " begin waiting!");  
  4.                     long waitTime = System.currentTimeMillis();  
  5.                     try {  
  6.                         flag.wait();  
  7.                     } catch (InterruptedException e) {  
  8.                         e.printStackTrace();  
  9.                     }  
  10.                     waitTime = System.currentTimeMillis() - waitTime;  
  11.                     System.out.println("wait time :"+waitTime);  
  12.                 }  
  13.                 System.out.println(getName() + " end waiting!");  
  14.             }  

 

We're a step forward.

Has the problem been solved?

It seems that java.lang.IllegalMonitorStateException is still running or failing.what happened?

 

The exception at this point is caused by changing the state of the flag object in the synchronization block for the flag object.The following:

flag="false";

flag.notify();

The flag is assigned in the synchronization block so that the object referenced by the flag changes. When the notify method is called again, an exception is thrown because there is no control.

 

We can improve this by changing flag to a JavaBean and then changing its properties without affecting the reference to flag.

Let's try an array instead, and we can do the same:

 

 

  1. private   String flag[] = {"true"};  

 

 

  1. synchronized (flag) {  
  2.             flag[0] = "false";  
  3.             flag.notify();  
  4.         }  

 

 

  1. synchronized (flag) {  
  2.                 while (flag[0]!="false") {  
  3.                     System.out.println(getName() + " begin waiting!");  
  4.                     long waitTime = System.currentTimeMillis();  
  5.                     try {  
  6.                         flag.wait();  
  7.                           
  8.                     } catch (InterruptedException e) {  
  9.                         e.printStackTrace();  
  10.                     }  

 

 

Run again at this time and no exceptions will be reported, but the thread did not end, right, and the thread is blocked and in a wait state.

 

The simple reason is that we have three wait threads and only one notify thread. When the notify thread runs the notify method, it randomly notifies one waiting thread, so there should be two more waiting threads.

 

We just need to change the flag.notify() method in the NotifyThread thread class to notifyAll().The notifyAll method notifies all threads waiting for object control.

 

The final version is as follows:

 

 

    1. public class NotifyTest {  
    2.     private String flag[] = { "true" };  
    3.   
    4.     class NotifyThread extends Thread {  
    5.         public NotifyThread(String name) {  
    6.             super(name);  
    7.         }  
    8.   
    9.         public void run() {  
    10.             try {  
    11.                 sleep(3000);  
    12.             } catch (InterruptedException e) {  
    13.                 e.printStackTrace();  
    14.             }  
    15.             synchronized (flag) {  
    16.                 flag[0] = "false";  
    17.                 flag.notifyAll();  
    18.             }  
    19.         }  
    20.     };  
    21.   
    22.     class WaitThread extends Thread {  
    23.         public WaitThread(String name) {  
    24.             super(name);  
    25.         }  
    26.   
    27.         public void run() {  
    28.             synchronized (flag) {  
    29.                 while (flag[0] != "false") {  
    30.                     System.out.println(getName() + " begin waiting!");  
    31.                     long waitTime = System.currentTimeMillis();  
    32.                     try {  
    33.                         flag.wait();  
    34.   
    35.                     } catch (InterruptedException e) {  
    36.                         e.printStackTrace();  
    37.                     }  
    38.                     waitTime = System.currentTimeMillis() - waitTime;  
    39.                     System.out.println("wait time :" + waitTime);  
    40.                 }  
    41.                 System.out.println(getName() + " end waiting!");  
    42.             }  
    43.         }  
    44.     }  
    45.   
    46.     public static void main(String[] args) throws InterruptedException {  
    47.         System.out.println("Main Thread Run!");  
    48.         NotifyTest test = new NotifyTest();  
    49.         NotifyThread notifyThread = test.new NotifyThread("notify01");  
    50.         WaitThread waitThread01 = test.new WaitThread("waiter01");  
    51.         WaitThread waitThread02 = test.new WaitThread("waiter02");  
    52.         WaitThread waitThread03 = test.new WaitThread("waiter03");  
    53.         notifyThread.start();  
    54.         waitThread01.start();  
    55.         waitThread02.start();  
    56.         waitThread03.start();  
    57.     }  
    58.   

Reprinted at: https://www.cnblogs.com/leekenky/p/3649829.html

Topics: jvm Java