Reprint Please specify source:http://blog.csdn.net/ns_code/article/details/17229601
If a thread waits for a notification, but the thread waits for a condition that is not satisfied, the thread is given an early notification, and if the condition is satisfied for a short period of time, but changes again quickly and becomes no longer satisfied, an early notification will also occur. This behavior sounds strange, and the following is an example program to illustrate the problem.
Quite simply, two threads wait for the element in the list to be deleted while the other line is impersonating to add items to it. The code is as follows:
[Java]View PlainCopy
- Import java.util.*;
- Public class Earlynotify extends Object {
- private list List;
- Public earlynotify () {
- List = Collections.synchronizedlist (new LinkedList ());
- }
- Public String RemoveItem () throws interruptedexception {
- Print ("in RemoveItem ()-entering");
- synchronized (list) {
- if (List.isEmpty ()) { //Here is a danger with an if statement
- Print ("in RemoveItem ()-About to wait ()");
- List.wait ();
- Print ("in RemoveItem ()-Do with Wait ()");
- }
- //Delete element
- String item = (string) list.remove (0);
- Print ("in RemoveItem ()-leaving");
- return item;
- }
- }
- public void AddItem (String item) {
- Print ("in AddItem ()-entering");
- synchronized (list) {
- //Add element
- List.add (item);
- Print ("in AddItem ()-just added: '" + Item + "'");
- //Add, notify all threads
- List.notifyall ();
- Print ("in AddItem ()-Just notified");
- }
- Print ("in AddItem ()-leaving");
- }
- private static void print (String msg) {
- String name = Thread.CurrentThread (). GetName ();
- SYSTEM.OUT.PRINTLN (name + ":" + msg);
- }
- public static void Main (string[] args) {
- final earlynotify en = new earlynotify ();
- Runnable RunA = new Runnable () {
- public Void Run () {
- try {
- String item = En.removeitem ();
- Print ("in Run ()-returned: '" +
- Item + "'");
- } catch (Interruptedexception ix) {
- Print ("interrupted!");
- } catch (Exception x) {
- Print ("threw an Exception!!! \ n "+ x);
- }
- }
- };
- Runnable Runb = new Runnable () {
- public Void Run () {
- En.additem ("hello!");
- }
- };
- try {
- //Start the first thread to delete an element
- Thread threadA1 = new Thread (RunA, "threadA1");
- Threada1.start ();
- Thread.Sleep (500);
- //Start the second thread to delete an element
- Thread threadA2 = new Thread (RunA, "threadA2");
- Threada2.start ();
- Thread.Sleep (500);
- //Start thread that adds elements
- Thread threadb = new Thread (Runb, "threadb");
- Threadb.start ();
- Thread.Sleep (10000); //wait ten seconds
- Threada1.interrupt ();
- Threada2.interrupt ();
- } catch (Interruptedexception x) {}
- }
- }
The results of the implementation are as follows:
Analysis: First start threada1,threada1 call Wait () in RemoveItem () to release the object lock on the list. After 500ms, start threada2,threada2 call RemoveItem (), get the object lock on the list, and find that the list is empty, blocking at the wait () method, freeing the object lock on the list. After 500ms, start threadb, call AddItem, get the object lock on the list, add an element to the list, and notify all threads with Notifyall.
ThreadA1 and ThreadA2 both return from Wait (), wait for an object lock on the list object, and attempt to remove the added element from the listing, which can cause trouble and only one of the operations succeeds. Assuming that threadA1 acquires the object lock on the list and deletes the element successfully, when exiting the synchronized block, it frees the object lock on the list, and ThreadA2 acquires the object lock on the list, and continues to delete the elements in the list. But the list is empty, which throws indexoutofboundsexception.
To avoid this, simply change the IF statement of the wait perimeter to a while loop, so that when the list is empty, the thread will continue to wait instead of executing the code to delete the elements in the list.
The result of the modified execution is as follows:
Summary: When using the thread's wait/notification mechanism, it is generally necessary to call the wait () method in the while loop, so that the while loop exits when the condition is met, which generally also uses a Boolean variable (or any other condition that can determine the true or false). As in this article, List.isEmpty ()), when the condition of the while loop is met, enters the while loop, executes the wait () method, does not satisfy the condition of the while loop, and executes the subsequent code.
Go: "Java concurrency Programming" 12: Early Notification issues notifyall in inter-thread communication (with code)