Through synchronization, one thread can safely change values that another thread would read. How does the second thread know the values have changed? What If the second thread is waiting for the "values to" by rereading the values every few?
One not-so-good way that a thread can wait for a value to the change are by using a busy/wait:
while (GetValue ()!= desiredvalue) {
Thread.Sleep (500);
}
Such code is called a busy/wait because the thread are busy using up processor resources to continually check to if the Value has changed. To use fewer could is increased, but then the thread might not find out about the change for qui Te some time. On the other hand, if the "sleep" is reduced, the thread would find out sooner, but'll waste even more of the Processo R Resources. In Java, there are a much better way to handle this kind of situation:the wait/notify.
Sometimes we need communication between threads, like how does the second thread know that some of the values of the first thread have changed? A less-than-good approach, called busy/wait, is that by constantly looping and combining thread.sleep () test values are changed, the processor resources are consumed, and the frequency of the cycle is not easy to grasp, quickly wasting resources, slow down the reaction speed. In this case, a better solution is given in Java: the wait/notify mechanism
The wait/notify mechanism
The wait/notify mechanism allows one thread to wait for a notification from another thread, it may proceed.
Minimal wait/notify
At a bare minimum, you need the "object to lock" and two threads to implement the wait/notify mechanism.
Imagine that there are a variable, valuelock, that'll be used for synchronization:
Private Object Valuelock = new Object ();
The comes along and executes this code fragment:
Synchronized (Valuelock) {
try {
Valuelock.wait ();
catch (Interruptedexception x) {
System.out.println ("interrupted while Waiting");
}
}
The wait () method requires the calling thread to have previously acquired the ' Object-level lock on the target object. In this case, the object that'll be waited upon is valuelock, and two lines before the valuelock.wait () statement is the Synchronized (valuelock) statement. The thread that invokes the "Wait" () method releases the Object-level lock and goes to sleep until notified or interrupted. If The waiting thread is interrupted, it competes with the other threads to reacquire the Object-level lock and throws a Interruptedexception from Within (). If The waiting thread is notified, it competes with the other threads to reacquire the Object-level lock and then From the Wait ().
The wait () method needs to be invoked after obtaining object-level lock, or it throws a illegalmonitor-
Stateexception exception, when the thread calls the Wait () method, it releases object-level lock and then sleep () until it is notified or interrupted, if it is interrupted, This thread will again compete to get object-level lock, then throw interrruptedexception, if notified, this thread will regain the Object-level lock, return from Wait (), continue to execute wait () Future code.
Many times, a thread are interrupted to signal it this it should clean up and die (= 5). The statements used to-wait can is slightly rearranged to allow the interruptedexception to propagate up further:
try {
Synchronized (Valuelock) {
Valuelock.wait ();
}
catch (Interruptedexception x) {
System.out.println ("interrupted while Waiting");
Clean up, and allow thread to return from Run ()
}
Sometimes, a thread is interrupted in order to destroy it, and the interruptedexception exception can be deferred
Instead of catching interruptedexception, methods can simply declare that they throw it to pass the exception further up T He call chain:
If you do not catch an exception within the method, you can continue to toss it for later processing
The thread doing the notification comes along and executes this code fragment:
Synchronized (Valuelock) {
Valuelock.notify (); Notifyall () might be safer ...
}
This thread blocks until it can get exclusive access to the Object-level lock for Valuelock. After the "Lock is acquired", this thread notifies one of the waiting threads. If no threads are waiting, the notification effectively does nothing. If more than one thread are waiting on Valuelock, the thread scheduler arbitrarily chooses one to receive the notification. The other waiting threads are is not notified and continue to wait. To notify all waiting threads (instead of just one of the them), use Notifyall () (discussed later into this chapter).
First get Object-level lock, and then call Notify () to notify this object-level lock on one of all waiting threads, and if there is no waiting thread, the notification is invalid. If there is more than one waiting thread, the thread invocation mechanism selects one of the notifications, and the other waits for no notification. If you want to notify all waiting threads for this lock, apply Notifyall ()
Typical wait/notify
In most cases, a member variable are checked by the thread doing the waiting and modified by the thread doing the Notificat Ion. The checking and modification occur inside the synchronized blocks to is sure that no race conditions.
In most cases, it is a thread that waits for a member variable to satisfy a condition, and another thread to notify after modifying this member variable.
This time, the two member variables are used:
Private Boolean value = FALSE;
Private Object Valuelock = new Object ();
The value variable is checked by the thread doing the waiting and are set by the thread doing the notification. Synchronization on Valuelock controls concurrent access to value.
The comes along and executes this code fragment:
try {
Synchronized (Valuelock) {
while (value!= true) {
Valuelock.wait ();
}
Value is now true
}
catch (Interruptedexception x) {
System.out.println ("interrupted while Waiting");
}
After acquiring the ' Object-level lock for Valuelock, the ' the ' the ' the ' the ' the ' the ' the '. If It isn't, the thread executes wait (), releasing the Object-level lock. When this thread was notified, it wakes up, reacquires the lock, and returns from Wait (). To is sure that it is not falsely notified (the "Early Notification" discussion later), it chapter Es the while expression. If value is still not true, the thread waits again. If It is true, the thread continues to execute the rest of the code inside the synchronized block.
While the "the" is waiting, a second thread comes along and executes this code fragment:
Synchronized (Valuelock) {
Value = true;
Valuelock.notify (); Notifyall () might be safer ...
}
When the "executes" () method on Valuelock, it releases the Object-level lock it is holding. This release allows the "second thread to get exclusive access to" Object-level lock on Valuelock and enter the Synchron Ized block. Inside, the second thread sets value to True and invokes notify () on Valuelock to signal one waiting thread that value has been changed.
Wait/notify with synchronized Methods
Sometimes, the class is designed to synchronize on this instead of another object. In this case, the synchronized method modifier can be used instead of a synchronized statement. The following code fragments are an adaptation of the previous example.
If you are synchronizing this instead of synchronizing other objects, you can use synchronized method with the wait/notify mechanism in the class definition.
As before, a variable value is initially set to false:
Private Boolean value = FALSE;
The Threada comes along and invokes this Waituntiltrue () method:
Public synchronized void Waituntiltrue ()
Throws Interruptedexception {
while (value = = False) {
Wait ();
}
}
While Threada are blocked on the wait (), a second thread (THREADB) comes along and executes it, passing in true fo R newvalue:
Public synchronized void SetValue (Boolean newvalue) {
if (newvalue!= value) {,
value = newvalue;
Notify (); Notifyall () might be safer ...
}
}
Note this both methods are synchronized and are members of the same class. In addition, both threads are invoking methods to the same of this class. The Waituntiltrue () method (with the "Wait () inside") declares that it might throw a interruptedexception. In this case, when threadb passes at true, value is changed and notify () are used to signal the waiting Threada Proceed. Threada wakes up, reacquires the "Object-level lock on", returns from Wait (), and re-evaluates the while expression. This time, the value is true, and Threada would return the from Waituntiltrue ().
As above, two methods involving wait and notify in the class definition are defined as synchronized, and two threads can communicate with each other if two threads are calling the same instance of the class.
Object API Used for Wait/notify
The wait/notify mechanism is embedded deep in the heart of Java. Object, the superclass of all classes, has five methods that are the core of the Wait/notify mechanism:notify (), Notifyal L (), a Wait (), a wait (long), and a wait (long, int). All classes in Java inherit from Object, so all classes have this public methods available to them. Additionally, none of these methods can be overridden in a subclass as they all are final.
The parent class object of all classes in Java has a wait/notify mechanism built into the five core methods of the wait/notify mechanism:
Notify (), Notifyall (), wait (), wait (long), wait (long,int), so all classes in Java have these five methods, these five methods are public, and final, can not be overridden by the quilt class.
Notify ()
Public final native void Notify ()
Throws Illegalmonitorstateexception//RuntimeException
The Notify () method was used by a thread to signal any other threads that might being waiting on the object. If more than one thread are waiting on the object, the thread scheduler would arbitrarily choose exactly one to be notified, And the others would continue to wait. If no threads are currently waiting on the object, notify () has no effect. Before invoking notify (), a thread must get exclusive access to the Object-level lock for the object. Unlike wait (), the invocation of notify () does not temporarily release the lock. If The proper lock is isn't held when notify () is called, a illegalmonitorstateexception is thrown. This exception is a subclass of the runtimeexception, so a try-catch construct are not necessary and is rarely used.
The Notify () method is used to notify all other threads waiting on their semaphore. If more than one thread is waiting, one is selected to be notified, the other continues to wait, and this method is invalid if no thread is waiting. Calling notify () does not release the lock like Wait (), but instead waits for the lock to be released. If the call to notify () is not holding the proper lock, it throws the Illegalmonitorstateexception (RuntimeException subclass without Try/catch)
Notifyall ()
Public final native void Notifyall ()
Throws Illegalmonitorstateexception//RuntimeException
The Notifyall () method works the same as notify () (to above) with one important Exception:when () is Notifyall, a ll the threads waiting on the object are notified and not just one. The advantage of Notifyall () is, you don ' t have. Concerned about which one of the waiting threads would be notifie D-they'll all is notified. The disadvantage is it might being wasteful (in terms of processor resources) to notify all the waiting threads if only One would actually be able to proceed. When in doubt, err on the side of safety over speed and use Notifyall () instead of notify ().
Notifyall () Notifies all waiting threads on the lock, whose disadvantages are obvious, and may waste processor resources if there is no need to notify all waiting threads. Based on security rather than speed considerations, you should use Notifyall () instead of notify ().
Wait ()
Public final void Wait ()
Throws Interruptedexception,
Illegalmonitorstateexception//RuntimeException
The wait () is used to put the "current thread" to "until it is notified or interrupted. Before invoking Wait (), a thread must get exclusive access to the Object-level lock for the object. Just after entering wait (), the current thread releases the lock. Before returning from Wait (), the thread competes with the other threads to reacquire the lock. If The proper lock is isn't held when wait () is called, a illegalmonitorstateexception is thrown. This exception is a subclass of the runtimeexception, so a try-catch construct are not necessary and is rarely used.
If The waiting thread is interrupted, it competes to reacquire the lock and throws a interruptedexception from within Wai T (). This exception isn't a subclass of RuntimeException, so a try-catch construct is required.
Wait () to sleep the current thread until it is notified or interrupted.
Before calling Wait (), the thread must exclusive access to the object's Object-level lock.
As soon as you enter Wati (), the current thread releases Object-level lock.
The thread again competes with other threads to obtain this lock before wait () returns.
If you call wait () without holding the proper lock, you throw a illegalmonitorstateexception.
If the waiting thread is interrrupted, it will regain the lock and then throw the interrruptedexception, which is not a runtimeexception subclass, so it must be try/catch.
Wait (long)
Public final native void wait (long mstimeout)
Throws Interruptedexception,
Illegalmonitorstateexception,//RuntimeException
IllegalArgumentException//RuntimeException
The "Wait (long)" is used to put the "current thread" to "until it is notified, interrupted, or the specified Timeo UT elapses. The other than the timeout, and wait (long) behaves the same as wait (). The argument mstimeout specifies the maximum number of milliseconds the thread should wait for notification. If mstimeout is 0, the thread would never time out (just like wait ()). If The argument is less than 0, a illegalargumentexception would be thrown. IllegalArgumentException is a subclass of the runtimeexception, so a try-catch the block isn't required and is rarely used.
Let the thread wait for a certain time, milliseconds, if the argument is set to 0, there is no time limit, if the parameter is less than 0, throw IllegalArgumentException exception, this exception is runtimeexception subclass, do not need try-catch
If the specified number of milliseconds elapses before the waiting thread is notified or interrupted, it competes to Reacq Uire the lock and returns from Wait (long). There is no way for the caller to determine whether a notification or a timeout occurred because no information (void) is Returned from (long).
If the waiting thread is not notified/interrupted within the set time, it will regain the lock and return from Wait (). The caller has no way of knowing whether to be notified or timed out, because wait (long) does not return a value.
Wait (long, int)
Public final void Wait (long mstimeout, int nanosec)
Throws Interruptedexception,
Illegalmonitorstateexception,//RuntimeException
IllegalArgumentException//RuntimeException
The "Wait" (long, int) method works just like wait (long, int) ("above") with the exception that nanoseconds can is added to The timeout value. The argument nanosec is added to Mstimeout to determine the total amount of the the thread would wait for Notificatio N before returning. A nanosecond is One-billionth of a second (10E-9), and most common implementations to the Java VM don ' t truly support this Fine a resolution of time. For this reason, the use of the to is currently quite rare.
Same, wait (long), but the time setting is more precise, you can set the nanosecond number, but the general virtual machine does not implement this method.
When to use Notifyall () Instead of Notify ()
The fundamental difference between notify () and Notifyall () is so if more than one thread are simultaneously waiting for Notification, notify () 'll provide notification to only one of the waiting threads, whereas Notifyall () 'll provide Noti Fication to all of them. If your code is defended against early notifications (discussed later), Notifyall () is generally the better choice.
The major disadvantage of Notifyall () is, it is wasteful to processor resources if all but one of the notified threads 'll end up waiting again. This is a situation it difficult to guarantee. If your code synchronizes on this either through synchronized blocks or the synchronized method, you can ' t be modifier e that some code external to the class won ' t synchronize and wait on a reference to the object. If that is happens, notify () might signal the thread running that external code instead to the thread that you intended. Consider a situation where you have a class, CLASSX, with two methods:
The same lock has a different locking method, the class inside the lock, the external class can also give instances of this class lock, multiple threads waiting for this lock, notify () does not necessarily notify the expected thread.
The following two synchronized methods are included in the class CLASSX, including the wait/notify
Public synchronized void Waituntiltrue ()
Throws Interruptedexception {
while (value = = False) {
Wait ();
}
}
Public synchronized void SetValue (Boolean newvalue) {
if (newvalue!= value) {
value = newvalue;
Notify (); Notifyall () might be safer ...
}
}
At the same time, there is an external class classy, which generates an instance of CLASSX, and a wait on this instance ()
In addition, there ' a external class, classy, with this code in one's its methods:
CLASSX cx = new CLASSX ();
Cx.setvalue (FALSE);
// ...
Synchronized (CX) {
Cx.wait (); Trouble
}
If Threada is running inside classy, it synchronizes on CX and invokes wait (). If threadb invokes Waituntiltrue (), it is now also waiting for notification. If THREADC invokes SetValue () and passes true (a new value), Threadc'll only notify one thread because Notifyall () wasn ' T used. There ' s no way to be sure whether Threada or threadb'll be notified. In this situation, Notifyall () would have guaranteed that they would is both.
If there are three threads: Threada runs in classy, synchronizes CX and waits; THREADB calls CX's waituntiltrue () wait; THREADC calls CX's SetValue (), it can only notify one of the Threada,b There is no way to determine which one is notified. Notifyall () guarantees both are notified.
It is generally safe to use notify () only if you can guarantee this only one thread would ever be waiting for Notificatio N. This is a relatively unusual occurrence.
When there is only one thread, use the Notify ()
If you are not sure whether for your need to use Notify () or Notifyall (), use Notifyall (). It might be a little wasteful, but it ' s safer.
If you are unsure which one to use, use Notifyall ().
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.