Java Thread Programming 1.8.2 – Inter-thread Communication
來源:互聯網
上載者:User
Missed Notification A missed notification occurs when threadB tries to notify threadA, but threadA is not yet waiting for the notification. In a multithreaded environment like Java, you don’t have much control over which thread runs and for how long. This uncertainty can lead to a situation in which most of the time an application is run, threadA is waiting before threadB does the notification. But occasionally, threadB does the notification before threadA is waiting. This missed notification scenario can be quite dangerous. Missed Notification指:線程B試圖通知線程A,但線程A並沒有在等待通知。這並不是不可能出現的。在多線程環境中,我們不能控制哪個線程執行,執行多長時間,這種不確定有可能導致在一個線程等待之前就先行通知,這是一種很危險的情況。如下程式會出現這種情況: /* * Created on 2005-7-14 * * Java Thread Programming - Paul Hyde * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 * */package org.tju.msnrl.jonathan.thread.chapter8; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo * blog.yesky.net/jonathanundersun * * Enjoy Life with Sun! * */public class MissedNotify { private Object proceedLock; public MissedNotify(){ proceedLock = new Object(); } public void waitProceed() throws InterruptedException{ print("in waitProceed() - begin"); synchronized(proceedLock){ print("begin synchronized wait ..."); proceedLock.wait(); print("end synchronized wait ..."); } print("in waitProceed() - end"); } public void notifyProceed(){ print("in notifyProceed() - begin"); synchronized(proceedLock){ print("begin synchronized notify ..."); proceedLock.notifyAll(); print("end synchronized notify ..."); } print("in notifyProceed() - end"); } public static void print(String msg){ String temp = Thread.currentThread().getName(); System.out.println(temp + " - " + msg); } public static void main(String[] args) { final MissedNotify mn = new MissedNotify(); Runnable runA = new Runnable(){ public void run(){ try{ Thread.sleep(1000);//wait()後執行 mn.waitProceed(); }catch(InterruptedException e){ e.printStackTrace(); } } }; Thread threadA= new Thread(runA,"threadA"); threadA.start(); Runnable runB = new Runnable(){ public void run(){ try{ Thread.sleep(500);//notify()先執行 mn.notifyProceed(); }catch(InterruptedException e){ e.printStackTrace(); } } }; Thread threadB = new Thread(runB,"threadB"); threadB.start(); try{ Thread.sleep(10000); }catch(InterruptedException e){ } print("interrupt thread A ..."); threadA.interrupt(); }} 輸出結果:threadB - in notifyProceed() - beginthreadB - begin synchronized notify ...threadB - end synchronized notify ...threadB - in notifyProceed() - endthreadA - in waitProceed() - beginthreadA - begin synchronized wait ...main - interrupt thread A ...java.lang.InterruptedException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:429) at org.tju.msnrl.jonathan.thread.chapter8.MissedNotify.waitProceed(MissedNotify.java:35) at org.tju.msnrl.jonathan.thread.chapter8.MissedNotify$1.run(MissedNotify.java:66) at java.lang.Thread.run(Thread.java:534) 解決方案:只需加一個標誌位: /* * Created on 2005-7-14 * * Java Thread Programming - Paul Hyde * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 * */package org.tju.msnrl.jonathan.thread.chapter8; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo * blog.yesky.net/jonathanundersun * * Enjoy Life with Sun! * */public class MissedNotifyFix { private Object proceedLock; private boolean okToProceed; public MissedNotifyFix(){ okToProceed = false; proceedLock = new Object(); } public void waitProceed() throws InterruptedException{ print("in waitProceed() - begin"); synchronized(proceedLock){ while(!okToProceed){ print("begin synchronized wait ..."); proceedLock.wait(); print("end synchronized wait ..."); } } print("in waitProceed() - end"); } public void notifyProceed(){ print("in notifyProceed() - begin"); synchronized(proceedLock){ okToProceed = true; print("begin synchronized notify ..."); proceedLock.notifyAll(); print("end synchronized notify ..."); } print("in notifyProceed() - end"); } public static void print(String msg){ String temp = Thread.currentThread().getName(); System.out.println(temp + " - " + msg); } public static void main(String[] args) { final MissedNotifyFix mn = new MissedNotifyFix(); Runnable runA = new Runnable(){ public void run(){ try{ Thread.sleep(1000); mn.waitProceed(); }catch(InterruptedException e){ e.printStackTrace(); } } }; Thread threadA= new Thread(runA,"threadA"); threadA.start(); Runnable runB = new Runnable(){ public void run(){ try{ Thread.sleep(500); mn.notifyProceed(); }catch(InterruptedException e){ e.printStackTrace(); } } }; Thread threadB = new Thread(runB,"threadB"); threadB.start(); try{ Thread.sleep(10000); }catch(InterruptedException e){ } print("interrupt thread A ..."); threadA.interrupt(); }} 輸出結果:threadB - in notifyProceed() - beginthreadB - begin synchronized notify ...threadB - end synchronized notify ...threadB - in notifyProceed() - endthreadA - in waitProceed() - beginthreadA - in waitProceed() - endmain - interrupt thread A ...
Early Notification
If a thread is notified while waiting, but the condition the thread is waiting for has not yet been met, the thread has received an
early notification. An early notification can also occur if the condition is briefly met but quickly changes so it’s no longer met. This might sound strange, but early notification can happen due to subtle errors in the code (generally when an if is used instead of a while). Early notification是指:當一個等待線程被通知的時候,它等待的條件不再滿足,這時我們說,線程收到了一個early notification。Early notification在等待的條件瞬間滿足然後立刻改變不再滿足時,也會發生。通常在一個需要使用while的地方使用了if。 Early notification的代碼:/* * Created on 2005-7-14 * * Java Thread Programming - Paul Hyde * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 * */package org.tju.msnrl.jonathan.thread.chapter8; import java.util.*; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo * blog.yesky.net/jonathanundersun * * Enjoy Life with Sun! * */public class EarlyNotify { private List list; public EarlyNotify(){ list = Collections.synchronizedList(new LinkedList()); } public String removeItem() throws InterruptedException{ print("entering removeItem()..."); synchronized(list){ if(list.isEmpty()){ print("list wait ... begin"); list.wait(); print("list wait ... end"); } String item = (String)list.remove(0); print("leaveing removeItem() ..."); return "you remove " + item; } } public void addItem(String item){ print("entering addItem() ..."); synchronized(list){ list.add(item); print("list notify ... begin"); list.notifyAll(); print("list notify ... end"); } print("leave addItem() ..."); } public static void print(String msg){ String temp = Thread.currentThread().getName(); System.out.println(temp + " - " + 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() remove item " + item); }catch(InterruptedException e1){ print("interrupted"); }catch(Exception e2){ print("exception" + e2.getMessage()); } } }; Runnable runB = new Runnable(){ public void run(){ en.addItem("hello"); } }; try{ Thread threadA = new Thread(runA,"threadA"); threadA.start(); Thread.sleep(500); Thread threadB = new Thread(runA,"threadB"); threadB.start(); Thread.sleep(500); Thread threadC = new Thread(runB,"threadC"); threadC.start(); Thread.sleep(10000); threadA.interrupt(); threadB.interrupt(); }catch(InterruptedException e1){ }catch(Exception e2){ } }} 輸出結果:threadA - entering removeItem()...threadA - list wait ... beginthreadB - entering removeItem()...threadB - list wait ... beginthreadC - entering addItem() ...threadC - list notify ... beginthreadC - list notify ... endthreadA - list wait ... endthreadA - leaveing removeItem() ...threadA - in run() remove item you remove hellothreadB - list wait ... endthreadC - leave addItem() ...threadB - exceptionIndex: 0, Size: 0 正確的代碼:/* * Created on 2005-7-14 * * Java Thread Programming - Paul Hyde * Copyright ? 1999 Sams Publishing * Jonathan Q. Bo 學習筆記 * */package org.tju.msnrl.jonathan.thread.chapter8; import java.util.*; /** * @author Jonathan Q. Bo from TJU MSNRL * * Email:jonathan.q.bo@gmail.com * Blog:blog.csdn.net/jonathan_q_bo * blog.yesky.net/jonathanundersun * * Enjoy Life with Sun! * */public class EarlyNotifyFix { private List list; public EarlyNotifyFix(){
list = Collections.synchronizedList(new LinkedList()); } public String removeItem() throws InterruptedException{ print("entering removeItem()..."); synchronized(list){
while(list.isEmpty()){//use while instead of if print("list wait ... begin");
list.wait(); print("list wait ... end"); } String item = (String)list.remove(0); print("leaveing removeItem() ..."); return "you remove " + item; } } public void addItem(String item){ print("entering addItem() ..."); synchronized(list){ list.add(item); print("list notify ... begin");
list.notifyAll(); print("list notify ... end"); } print("leave addItem() ..."); } public static void print(String msg){ String temp = Thread.currentThread().getName(); System.out.println(temp + " - " + msg); } public static void main(String[] args) { final EarlyNotifyFix en = new EarlyNotifyFix(); Runnable runA = new Runnable(){ public void run(){ try{ String item = en.removeItem(); print("in run() remove item " + item); }catch(InterruptedException e1){ print("interrupted"); }catch(Exception e2){ print("exception" + e2.getMessage()); } } }; Runnable runB = new Runnable(){ public void run(){ en.addItem("hello"); } }; try{ Thread threadA = new Thread(runA,"threadA"); threadA.start(); Thread.sleep(500); Thread threadB = new Thread(runA,"threadB"); threadB.start(); Thread.sleep(500); Thread threadC = new Thread(runB,"threadC"); threadC.start(); Thread.sleep(10000); threadA.interrupt(); threadB.interrupt(); }catch(InterruptedException e1){ }catch(Exception e2){ } }} 輸出結果:threadA - entering removeItem()...threadA - list wait ... beginthreadB - entering removeItem()...threadB - list wait ... beginthreadC - entering addItem() ...threadC - list notify ... beginthreadC - list notify ... endthreadA - list wait ... endthreadA - leaveing removeItem() ...threadA - in run() remove item you remove hellothreadB - list wait ... endthreadB - list wait ... beginthreadC - leave addItem() ...threadB - interrupted