Java Thread Programming 1.8.1-Inter-thread Communication

Source: Internet
Author: User
The need for inter-thread Signaling  Through synchronization, one thread can safely change values that another thread will read. How does the second thread know that the values have changed? What if the second thread is waiting for the values to change by rereading the values every few seconds? One not-so-good way that a thread can wait for a value to change is by using Busy/Wait: While (getValue ()! = DesiredValue) {Thread. sleep (500);} Such code is called a busy/wait because the thread is busy using up processor resources to continually check to see if the value has changed. to use fewer resources, the sleep time cocould be increased, but then the thread might not find out about the change for quite some time. on the other hand, if the sleep time is already CED, the thread will find out sooner, but will waste even more of the processor resources. in Java, there is a much better way to handle this kind of situation: Wait/notifyMechanic. Sometimes we need communication between threads. For example, how does the second thread know that some values of the first thread have changed? This is not a good method. It is called busy/wait. if the sleep () test value changes, it will occupy processor resources, and the cycle frequency is not easy to grasp, which is a waste of resources and slow down the response speed. In this case, java provides a better solution: wait/notify Mechanism The wait/notify mechanic  The wait/notify mechanic allows one thread to wait for a notification from another thread that it may proceed. Minimal wait/notifyAt a bare minimum, you need an object to lock on and two threads to implement the wait/notify mechanic. imagine that there is a member variable, valueLock, that will be used for synchronization: private Object Valuelock= New Object (); The first thread comes along and executes this code fragment: Synchronized(ValueLock) {try {valueLock. Wait ();} Catch ( InterruptedexceptionX) {System. out. println ("interrupted while waiting") ;}} The wait () method requires the calling thread to have previusly acquired the object-level lock on the target object. in this case, the object that will 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 an InterruptedException from within wait (). if the waiting thread is notified, it competes with the other threads to reacquire the object-level lock and then returns from wait (). the Wait () method can be called only after the object-level lock is obtained. Otherwise, the Illega LMonitor-StateException exception. When the thread calls the wait () method, the object-level lock is released, and then sleep () until it is notified or interrupted. If it is interrupted, this thread will compete again to get the object-level lock, and then throw InterrruptedException. If it is notified, this thread will compete again to get the object-level lock, which will be returned from wait, continue to run the code after wait. When times, a thread is interrupted to signal it that it shoshould clean up and die (see Chapter 5 ). the statements used to wait can be 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 to destroy and clear it, And the InterruptedException exception delay can be processed Instead of catching InterruptedException, methods can simply declare that they throw it to pass the exception further up the call chain: public void someMethod () throws Interruptedexception{//... Synchronized(ValueLock) {valueLock. Wait ();} //...} If an exception is not caught in The method, you can continue to throw the exception and leave it for future processing of The thread doing the notification comes along and executes this code fragment: Synchronized(ValueLock) {valueLock. Notify (); // Policyall () 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 OneOf the waiting threads. If no threads are waiting, the notification provided tively does nothing. If more than one thread is waiting on valueLock, the thread scheduler arbitrarily chooses OneTo receive the notification. The other waiting threads are not notified and continue to wait. To inform y AllWaiting threads (instead of just one of them), use policyall () (discussed later in this chapter ). first, you need to get the object-level lock, and then call wait y () to notify this object-level lock of one of all the waiting threads. If there is no waiting thread, the notification is invalid. If there are multiple waiting threads, select one of the notifications for the thread calling mechanism, and continue waiting for others that have not been notified. If you want to notify all the waiting threads for this lock, notifyAll () applies () Typical wait/notify  In most cases, a member variable is checked by the thread doing the waiting and modified by the thread doing the notification. the checking and modification occur inside the synchronized blocks to be sure that no race conditions develop. in most cases, a thread waits for a member variable to meet a certain condition, and the other thread modifies the member variable and then sends a notification. This time, 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 is set by the thread doing the notification. synchronization on valueLock controls concurrent access to value. the first thread 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 first thread checks value to see if it is true. if it is not, the thread executes wait (), releasing the object-level lock. when this thread is notified, it wakes up, reacquires the lock, and returns from wait (). to be sure that it was not falsely notified (see the "Early Notification" discussion later in this chapter), it re-evaluates 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 first thread is waiting, a second thread comes along and executes this code fragment: Synchronized (valuelock ){ Value= True; ValueLock. Policy(); // Policyall () might be safer ...} when the first thread executes the wait () method on valuelock, it releases the object-Level Lock it was holding. this release allows the second thread to get exclusive access to the object-Level Lock on valuelock and enter the synchronized block. inside, the second thread sets value to true and invokes every Y () on valuelock to signal OneWaiting 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 want to synchronize this instead of other objects, you can use the Synchronized Method in conjunction with the wait/notify mechanism in the class definition. As before, a member variable value is initially set to false: Private Boolean Value= False; the first thread (threada) comes along and invokes this waituntiltrue () method: Public SynchronizedVoid waituntiltrue () throws InterruptedException{While ( Value= False ){ Wait ();} While threada is blocked on the wait (), a second thread (threadb) comes along and executes this method, passing in true for newvalue: Public SynchronizedVoid setvalue (Boolean newvalue) {If (newvalue! = Value ){, Value= Newvalue; Notify ();// Policyall () might be safer...} note that both methods are synchronized and are members of the same class. In addition, both threads are invoking methods on the same InstanceOf this class. the waitUntilTrue () method (with the wait () inside) declares that it might throw an InterruptedException. in this case, when threadB passes in true, value is changed and every Y () is used to signal the waiting threadA that it may proceed. threadA wakes up, reacquires the object-level lock on this, returns from wait (), and re-evaluates the while expression. this time, value is true, D threadA will return from waitUntilTrue (). as mentioned above, both methods related to wait and ipvy in the class definition are defined as synchronized. If both threads call the same instance of this class, the two threads can communicate with each other. Object API Used for Wait/Notify  The wait/notify mechanic 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 Mechanic: Policy (), policyall (), wait (), wait (long ), and wait (long, INT ). all classes in Java inherit from object, so all classes have these public methods available to them. additionally, none of these methods can be overridden in a subclass As they are all declared final. in Java, the parent class object of all classes has the built-in wait/notify mechanism, which has five core methods of the built-in wait/it y mechanism: Notify (), policyall (), wait (), wait (long), wait (long, INT), so all classes in Java have these five methods. These five methods are public and final, and cannot be overwritten by the quilt class. Notify ()Public Final NativeVoid y () throws IllegalMonitorStateException// RuntimeException The specified y () method is used by a thread to signal any other threads that might be waiting on the object. if more than one thread is waiting on the object, the thread schedwill will arbitrarily choose exactly one to be notified, and the others will continue to wait. if no threads are currently waiting on the object, then Y () has no effect. before invoking Policy (), a thread must get exclusive access to the object-level lock for the object. unlike wait (), the invocation of Parameter Y () does NotTemporarily release the lock. If The proper lockIs not held when notify () is called, an IllegalMonitorStateException is thrown. this exception is a subclass of RuntimeException, so a try-catch construct is not necessary and is rarely used. the Y () method is used to notify all other threads waiting on the semaphore. If there is more than one thread waiting, one of them will be selected for notification, and the other will continue waiting. If there is no thread waiting, this method is invalid. Calling notify () does not release the lock like wait (), but waits for the lock to be released. If the call to policy () is not holding a proper lock, IllegalMonitorStateException (subclass of RuntimeException, do not try/catch) is thrown) Policyall ()Public Final NativeVoid policyall () Throws illegalmonitorstateexception // runtimeexception The policyall () method works the same as your Y () (see above) with one important exception: When policyall () is invoked, AllThe threads waiting on the object are notified, not just one. The advantage of policyall () is that you don't have to be concerned about which OneOf the waiting threads will be notified-they will AllBe notified. the disadvantage is that it might be wasteful (in terms of processor resources) to handle Y all the waiting threads if only one will actually be able to proceed. when in doubt, err on the side of safety over speed and use policyall () instead of policy (). notifyall () notifies all waiting threads that are locked. Its disadvantage is obvious. If it is not necessary to notify all waiting threads, processor resources may be wasted. You should use policyall () instead of policy () for security rather than speed considerations (). Wait ()Public FinalVoid wait () throws interruptedexception, Illegalmonitorstateexception // runtimeexception  The wait () method is used to put the current thread to sleep 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 ReleasesThe lock. before returning from wait (), the thread competes with the other threads to reacquire the lock. if the proper lock is not held when wait () is called, an illegalmonitorstateexception is thrown. this exception is a subclass of runtimeexception, so a try-catch construct is not necessary and is rarely used.  If the waiting thread is interrupted, it competes to reacquire the lock and throws an interruptedexception from within wait (). This exception is NotA subclass of RuntimeException, so a try-catch construct is required.  Wait () sleep the current thread until it is notified or interrupted. Before calling wait (), the thread must exclusive the object-level lock of the object. When wati () is entered, the current thread releases the object-level lock. Before wait () returns, the thread retries to compete with other threads to obtain this lock. If wait () is called without an appropriate lock, IllegalMonitorStateException is thrown. If the waiting thread is interrrupted, the lock is obtained again and InterrruptedException is thrown. This exception is not a subclass of RuntimeException, so try/catch is required.   Wait (long)Public final native void wait (long msTimeout) Throws InterruptedException, IllegalMonitorStateException, // RuntimeException IllegalArgumentException // RuntimeException  The wait (long) method is used to put the current thread to sleep until it is notified, interrupted, or the specified Timeout elapses. other than the timeout, wait (long) behaves the same as wait () (see abve ). the argument mstimeout specifies the maximum number of milliseconds that the thread shoshould wait for notification. if mstimeout is 0, the thread will never time out (just like wait ()). if the argument is less than 0, an illegalargumentexception will be thrown. illegalargumentexception is a subclass of runtimeexception, so a try-Catch Block is not required and is rarely used. let the thread wait for a certain period of time, in milliseconds. If the parameter is set to 0, there is no time limit. If the parameter is smaller than 0, an illegalargumentexception exception is thrown. This exception is a subclass of runtimeexception, try-catch is not required  If the specified number of milliseconds elapses before the waiting thread is notified or interrupted, it competes to reacquire 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 wait (long ). if the waiting thread is not notified/interrupted within the set time, the lock is obtained again and then returned from wait. The caller cannot know whether it is 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) (see above) with the exception that nanoseconds can be added to the timeout value. the argument nanoSec is added to msTimeout to determine the total amount of time that the thread will wait for notification before returning. A nanosecond is one-billionth of a second (10E-9), and most common implementations of the Java VM don't truly support This fine a resolution of time. for this reason, the use of the method is currently quite rare. same as wait (long), but the time setting is more precise and the number of nanoseconds can be set. However, this method is not generally implemented by virtual machines. When to Use policyall () Instead of policy ()  The fundamental difference between Y () and policyall () is that if more than one thread is simultaneously waiting for notification, every Y () will provide notification to only one of the waiting threads, whereas policyall () will provide notification to all of them. if your code is well defended against early communications (discussed later), policyall () is generally the better choice. the major d Isadvantage of policyall () is that it is wasteful of processor resources if all but one of the notified threads will end up waiting again. this is a situation that is difficult to guarantee. if your code synchronizes on this either through synchronized blocks or the synchronized method modifier, you can't be sure that some code external to the class won't synchronize and wait on a reference to Object. if that happens, Policy () might signal the thread running that external code instead of the thread that you intended. consider a situation where you have a class, ClassX, with two methods: the same lock has different locking methods. The class locks this internally, and the external class can also lock such instances, when multiple threads wait for this lock, notify () does not necessarily notify the expected thread. ClassX includes the following two synchronized methods: SynchronizedVoid waitUntilTrue () throws InterruptedException{While ( Value= False) {wait () ;}} public SynchronizedVoid setValue (boolean newValue) {if (newValue! = Value ){ Value= NewValue; Notify ();// Policyall () might be safer ...}} at the same time, there is an external class ClassY that generates the ClassX instance. In this instance, wait () In addition, there's an external class, ClassY, with this code in one of 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 will only have y one thread because policyall () wasn' t used. there's no way to be sure whether threadA or threadB will be notified. in this situation, policyall () w Ocould have guaranteed that they wowould both be notified. at this time, if there are three threads: threadA runs in ClassY, synchronize cx and wait; threadB calls cx's waitUntilTrue () wait; threadC calls cx's setValue (), it can only notify threadA, one of B has no way to determine which one is notified. Yyall () ensures that both are notified. It is generally safe to use your Y () only when you can guarantee that only one thread will ever be waiting for notification. this is a relatively unusual occurrence. when there is only one thread, use Policy () If you're not sure whether you need to use policy () or policyall (), use policyall (). it might be a little wasteful, but it's safer. if you are not sure which one to use, use policyall ().
Related Article

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.