1、線程交互的基礎知識
void notify():喚醒在此對象監視器上等待的單個線程。
void notifyAll():喚醒在此對象監視器上等待的全部線程。
void wait():致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或 notifyAll()方法。
固然,wait()還有另外兩個重載方法:
void wait(long timeout):致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或 notifyAll()方法,或者超過指定的時間量。
void wait(long timeout, int nanos):致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或 notifyAll()方法,或者其餘某個線程中斷當前線程,或者已超過某個實際時間量。ide
關於等待/通知,要記住的關鍵點是:
必須從同步代碼塊內調用wait()、notify()、notifyAll()方法。線程不能調用對象上等待或通知的方法,除非它擁有那個對象的鎖。this
wait()、notify()、notifyAll()都是Object的實例方法。與每一個對象具備鎖同樣,每一個對象能夠有一個線程列表,他們等待來自該信號(通知)。線程經過執行對象上的wait()方法得到這個等待列表。從那時候起,它再也不執行任何其餘指令,直到調用對象的notify()方法爲止。若是多個線程在同一個對象上等待,則將只選擇一個線程(不保證以何種順序)繼續執行。若是沒有線程等待,則不採起任何特殊操做。spa
例子線程
package cn.thread; /** * 計算1+2+3 ... +100的和 * * @author 林計欽 * @version 1.0 2013-7-23 上午10:06:04 */ public class ThreadSum extends Thread { int total = 0; @Override public void run() { synchronized (this) { for (int i = 0; i < 101; i++) { total += i; } //(完成計算了)喚醒在此對象監視器上等待的單個線程,在本例中線程ThreadInteractionTest被喚醒 notify(); } } }
package cn.thread; /** * 線程的交互 * * @author 林計欽 * @version 1.0 2013-7-23 上午10:04:11 */ public class ThreadInteractionTest { public static void main(String[] args) { ThreadSum sum = new ThreadSum(); // 啓動計算線程 sum.start(); // 線程ThreadInteractionTest擁有sum對象上的鎖。 // 線程爲了調用wait()或notify()方法,該線程ThreadInteractionTest必須是那個對象鎖的擁有者 synchronized (sum) { try { System.out.println("等待對象sum完成計算。。。"); // 當前線程ThreadInteractionTest等待 sum.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sum對象計算的總和是:" + sum.total); } } }
等待對象sum完成計算。。。
sum對象計算的總和是:5050
注意:當在對象上調用wait()方法時,執行該代碼的線程當即放棄它在對象上的鎖。然而調用notify()時,並不意味着這時線程會放棄其鎖。若是線程仍然在完成同步代碼,則線程在移出以前不會放棄鎖。所以,只要調用notify()並不意味着這時該鎖變得可用。
2、多個線程在等待一個對象鎖時使用notifyAll()
在多數狀況下,最好通知等待某個對象的全部線程。若是這樣作,能夠在對象上使用notifyAll()讓全部在此對象上等待的線程衝出等待區,返回到可運行狀態。code
package cn.thread; /** * 計算1+2+3 ... +100的和 * * @author 林計欽 * @version 1.0 2013-7-23 上午10:06:04 */ public class ThreadSum2 extends Thread { int total = 0; @Override public void run() { synchronized (this) { for (int i = 0; i < 101; i++) { total += i; } //通知全部在此對象上等待的線程 notifyAll(); } } }
package cn.thread; /** * 線程的交互 * * @author 林計欽 * @version 1.0 2013-7-23 上午10:04:11 */ public class ThreadInteractionTest2 extends Thread{ ThreadSum2 sum; public ThreadInteractionTest2(ThreadSum2 sum){ this.sum=sum; } @Override public void run() { synchronized (sum) { try { System.out.println("等待對象sum完成計算。。。"); // 當前線程ThreadInteractionTest等待 sum.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sum對象計算的總和是:" + sum.total); } } public static void main(String[] args) { ThreadSum2 sum = new ThreadSum2(); //啓動三個線程,分別獲取計算結果 new ThreadInteractionTest2(sum).start(); new ThreadInteractionTest2(sum).start(); new ThreadInteractionTest2(sum).start(); // 啓動計算線程 sum.start(); } }
等待對象sum完成計算。。。 等待對象sum完成計算。。。 等待對象sum完成計算。。。 sum對象計算的總和是:5050 sum對象計算的總和是:5050 sum對象計算的總和是:5050
談一下synchronized和wait()、notify()等的關係:
一、有synchronized的地方不必定有wait,notify
二、有wait,notify的地方必有synchronized.這是由於wait和notify不是屬於線程類,而是每個對象都具備的方法,並且,這兩個方法都和對象鎖有關,有鎖的地方,必有synchronized。
另外,注意一點:若是要把notify和wait方法放在一塊兒用的話,必須先調用notify後調用wait,由於若是調用完wait,該線程就已經不是currentthread了。對象