Java Multithreading-Thread communication

Source: Internet
Author: User

The goal of thread communication is to enable threads to send signals to each other. Thread communication, on the other hand, enables threads to wait for signals from other threads.

    1. Communicating through shared objects
    2. Busy waiting
    3. Wait (), notify () and Notifyall ()
    4. Loss of Signal
    5. False Wakeup
    6. Multithreading waits for the same signal
    7. Do not call Wait () on a constant string or global object
Communicating through shared objects

A simple way to send signals between threads is to set the signal value in the variables of the shared object. Thread A sets the Boolean member variable hasdatatoprocess to true in a synchronous block, and thread B reads the hasdatatoprocess member variable in the synchronization block. This simple example uses a signal-holding object and provides a set and check method:

public class mysignal{  protected Boolean hasdatatoprocess = false;  Public synchronized Boolean hasdatatoprocess () {    return this.hasdatatoprocess;  }  Public synchronized void Sethasdatatoprocess (Boolean hasData) {    this.hasdatatoprocess = HasData;  }}

Threads A and B must obtain a reference to a Mysignal shared instance for communication. If they hold references that point to different mysingal instances, they will not be able to detect each other's signals. The data that needs to be processed can be stored in a shared cache, which is stored separately from the Mysignal instances.

Busy Waiting (Busy wait)

Thread B preparing to process the data is waiting for the data to become available. In other words, it waits for a signal from thread A, and this signal causes hasdatatoprocess () to return true. Thread B runs in a loop to wait for this signal:

protected Mysignal sharedsignal = ... while (!sharedsignal.hasdatatoprocess ()) {  //do nothing ... busy waiting}
Wait (), notify () and Notifyall ()

Busy waiting does not make efficient use of the CPU running the waiting thread, unless the average wait time is very short. Otherwise, it is wiser to let the waiting thread go to sleep or non-running until it receives the signal it waits for.

Java has a built-in wait mechanism to allow threads to become non-operational when waiting for a signal. The Java.lang.Object class defines three methods, wait (), notify (), and Notifyall () to implement this wait mechanism.

Once a thread invokes the wait () method of any object, it becomes non-operational until another thread invokes the Notify () method of the same object. In order to call Wait () or notify (), the thread must first obtain the lock on that object. In other words, the thread must call Wait () or notify () in the synchronization block. The following is a modified version of Mysingal-mywaitnotify with Wait () and notify ():

public class Monitorobject{}public class mywaitnotify{  monitorobject mymonitorobject = new Monitorobject ();  public void dowait () {    synchronized (mymonitorobject) {      try{        mymonitorobject.wait ();      } catch ( Interruptedexception e) {...}  }} public void Donotify () {    synchronized (mymonitorobject) {      mymonitorobject.notify ();}}  }

The wait thread will call Dowait (), and the wake-up thread will call Donotify (). When a thread calls an object's Notify () method, a thread that is waiting for the object will be awakened and allowed to execute (glossing: The thread that will be awakened is random and cannot specify which thread to wake). It also provides a notifyall () method to wake all threads that are waiting for a given object.

As you can see, both the wait thread and the wake-up thread call Wait () and notify () in the synchronization block. This is mandatory! A thread cannot call wait (), notify (), or notifyall () if it does not hold an object lock. Otherwise, a Illegalmonitorstateexception exception is thrown.

( glossing: The JVM is so implemented that when you call wait it first checks to see if the current thread is the owner of the lock, not the one that throws the illegalmonitorstateexcept. )

But how is this possible? Does the wait thread hold the lock on the monitor object (Mymonitor object) While it executes inside the synchronization block? Does the wait thread not block the synchronization block that wakes the thread into donotify ()? The answer is: really not. Once the thread invokes the Wait () method, it releases the lock on the monitor object it holds. This will allow other threads to also call Wait () or notify ().

Once a thread is awakened, you cannot immediately exit the wait () method call until you call the Notify ()

public class mywaitnotify2{  monitorobject mymonitorobject = new Monitorobject ();  Boolean wassignalled = false;  public void dowait () {    synchronized (mymonitorobject) {      if (!wassignalled) {        try{          Mymonitorobject.wait ();         } catch (Interruptedexception e) {...}      }      Clear signal and continue running.      wassignalled = false;    }  }  public void Donotify () {    synchronized (mymonitorobject) {      wassignalled = true;      Mymonitorobject.notify ();}}}  

The thread exits its own synchronization block. In other words: The awakened thread must regain the lock on the monitor object before exiting the method call of Wait () because the wait method call runs inside the synchronization block. If multiple threads are awakened by Notifyall (), only one thread can exit the wait () method at the same time, because each thread must obtain a lock on the monitor object before exiting Wait ().

Lost Signal (Missed signals)

The Notify () and Notifyall () methods do not save the method that calls them, because there is a possibility that no thread is waiting when these two methods are called. After the notification signal is discarded. Thus, if a thread calls notify () before the notified thread calls Wait (), the waiting thread will miss the signal. This may or may not be a problem. However, in some cases, this may cause the waiting thread to wait forever and no longer wake up because the thread missed the wake-up signal.

In order to avoid losing signals, they must be kept in the signal class. In the mywaitnotify example, the notification signal should be stored in a member variable of the Mywaitnotify instance. The following is a modified version of Mywaitnotify:

public class mywaitnotify2{  monitorobject mymonitorobject = new Monitorobject ();  Boolean wassignalled = false;  public void dowait () {    synchronized (mymonitorobject) {      if (!wassignalled) {        try{          Mymonitorobject.wait ();         } catch (Interruptedexception e) {...}      }      Clear signal and continue running.      wassignalled = false;    }  }  public void Donotify () {    synchronized (mymonitorobject) {      wassignalled = true;      Mymonitorobject.notify ();}}}  

Note that the Donotify () method sets the wassignalled variable to True before calling notify (). Also, be aware that the dowait () method checks the wassignalled variable before calling wait (). In fact, if no signal is received in the time period between the previous dowait () call and the dowait () call, it will only call wait ().

(glossing: To avoid signal loss, use a variable to save whether it has been notified.) Before notify, set yourself to have been notified. After wait, the settings themselves have not been notified and need to wait for notification. )

False Wakeup

For inexplicable reasons, threads may wake up without calling Notify () and Notifyall (). This is called false wakeup (spurious wakeups). I woke up with no end.

If a false wake occurs in the Dowait () method of MyWaitNotify2, the waiting thread can perform subsequent operations even if it does not receive the correct signal. This can cause serious problems with your application.

To prevent false wakeup, the member variable that holds the signal is examined in a while loop, not in the IF expression. Such a while loop is called a spin lock (glossing: This is prudent, the current JVM implementation spin consumes the CPU, if the Donotify method is not called for a long time, the Dowait method will always spin and the CPU will consume too much). The awakened thread spins until the condition in the spin lock (while loop) becomes false. The revised version of the following MyWaitNotify2 shows this:

public class mywaitnotify3{  monitorobject mymonitorobject = new Monitorobject ();  Boolean wassignalled = false;  public void dowait () {    synchronized (mymonitorobject) {while      (!wassignalled) {        try{          Mymonitorobject.wait ();         } catch (Interruptedexception e) {...}      }      Clear signal and continue running.      wassignalled = false;    }  }  public void Donotify () {    synchronized (mymonitorobject) {      wassignalled = true;      Mymonitorobject.notify ();}}}  

Note that the wait () method is in a while loop, not in an if expression. If the waiting thread wakes without receiving a signal, the wassignalled variable changes to a false,while loop that executes again, prompting the waking thread to return to the waiting state.

Multiple threads waiting for the same signal

If you have multiple threads waiting to be awakened by Notifyall (), but only one is allowed to continue, using the while loop is a good way to do so. Only one thread can get a monitor object lock at a time, meaning that only one thread can exit the wait () call and clear the WASSIGNALLED flag (set to false). Once this thread exits the synchronization block of Dowait (), the other thread exits the wait () call and checks the value of the wassignalled variable in the while loop. However, this flag has been Cheng in addition to the first wake-up line, so the rest of the waking threads will return to the waiting state until the next signal arrives.

Do not call wait () in a string constant or global object

(glossing: A string constant in this chapter refers to a variable with a constant value)

A previous version of this article uses a string constant ("") as a pipe object in the mywaitnotify example. The following is the example:

public class mywaitnotify{  String mymonitorobject = "";  Boolean wassignalled = false;  public void dowait () {    synchronized (mymonitorobject) {while      (!wassignalled) {        try{          Mymonitorobject.wait ();         } catch (Interruptedexception e) {...}      }      Clear signal and continue running.      wassignalled = false;    }  }  public void Donotify () {    synchronized (mymonitorobject) {      wassignalled = true;      Mymonitorobject.notify ();}}}  

The problem with calling Wait () and notify () in an empty string as a synchronization block (or other constant string) for a lock is that the jvm/compiler internally converts the constant string to the same object. This means that even if you have 2 different mywaitnotify instances, they all reference the same empty string instance. It also implies the risk that a thread calling dowait () on the first mywaitnotify instance will be awakened by a thread calling Donotify () on the second mywaitnotify instance. This picture can be drawn as follows:

At first it might not be a big problem. After all, if Donotify () is called on the second mywaitnotify instance, what really happens is that threads a and B are woken up incorrectly. The awakened thread (A or B) will check the signal value in the while loop and return to the wait state because donotify () is not called on the first Mywaitnotify instance, which is exactly the instance it is waiting for. This is the equivalent of triggering a false wake-up. Thread A or B wakes up when the signal value is not updated. However, the code handles this situation, so the thread returns to the waiting state. Remember that even if 4 threads call Wait () and notify () on the same shared string instance, the signals in dowait () and donotify () are saved by 2 mywaitnotify instances respectively. A donotify () call on the MYWAITNOTIFY1 may wake the MyWaitNotify2 thread, but the signal value will only be stored in the MyWaitNotify1.

The problem is that because donotify () only calls notify () instead of notifyall (), even if there are 4 threads waiting on the same string (empty string) instance, only one thread is awakened. So, if thread A or B is awakened by a signal sent to C or D, it checks its signal value to see if there is a signal being received and then returns to the waiting state. Both C and D are not awakened to check the signal value they actually receive, so the signal is lost. This situation is equivalent to the previously mentioned loss of the signal problem. C and D have been sent signals, but none of them can respond to the signal.

If the Donotify () method calls Notifyall () instead of notify (), all waiting threads are awakened and the signal values are checked sequentially. Threads A and B return to the wait state, but C or D only one thread notices the signal and exits the dowait () method call. Another in C or D returns to the wait state because the thread that obtained the signal clears the signal value (set to false) while exiting Dowait ().

After seeing the above, you may try to use Notifyall () instead of notify (), but this is a bad idea in terms of performance. There is no reason to wake all threads every time that only one thread can respond to a signal.

So: in the Wait ()/notify () mechanism, do not use global objects, string constants, and so on. The corresponding unique object should be used. For example, each instance of MyWaitNotify3 has a monitor object that belongs to itself, instead of calling Wait ()/notify () on an empty string.

Turn from http://www.cnblogs.com/houziwty/p/5826598.html (written very well)

Java Multithreading-Thread communication

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.