標籤:
首先介紹幾個概念:
wait()方法
wait()方法使得當前線程必須要等待,等到另外一個線程調用notify()或者notifyAll()方法。
當前的線程必須擁有當前對象的monitor,也即lock,就是鎖。
線程調用wait()方法,釋放它對鎖的擁有權,然後等待另外的線程來通知它(通知的方式是notify()或者notifyAll()方法),這樣它才能重新獲得鎖的擁有權和恢複執行。
要確保調用wait()方法的時候擁有鎖,即,wait()方法的調用必須放在synchronized方法或synchronized塊中。
與sleep比較:
當線程調用了wait()方法時,它會釋放掉對象的鎖。
另一個會導致線程暫停方法:Thread.sleep(),它會導致線程睡眠指定的毫秒數,但線程在睡眠的過程中是不會釋放掉對象的鎖的。
notify()方法
notify()方法會喚醒一個等待當前對象的鎖的線程。
如果多個線程在等待,它們中的一個將會選擇被喚醒。這種選擇是隨意的,和具體實現有關。(線程等待一個對象的鎖是由於調用了wait方法中的一個)。
被喚醒的線程是不能被執行的,需要等到當前線程放棄這個對象的鎖。
被喚醒的線程將和其他線程以通常的方式進行競爭,來獲得對象的鎖。也就是說,被喚醒的線程並沒有什麼優先權,也沒有什麼劣勢,對象的下一個線程還是需要通過一般性的競爭。
notify()方法應該是被擁有對象的鎖的線程所調用。
換句話說,和wait()方法一樣,notify方法調用必須放在synchronized方法或synchronized塊中。
wait()和notify()方法要求在調用時線程已經獲得了對象的鎖,因此對這兩個方法的調用需要放在synchronized方法或synchronized塊中。
線程同步通訊實現demo:
傳統線程同步通訊技術,子線程迴圈10次,接著主線程迴圈100次,又回到子線程迴圈10次,接著再回到主線程又迴圈100次,如此迴圈50次
public class TraditionalThreadCommunication {/** * @param args */public static void main(String[] args) {final Business business = new Business();//建立了一個線程,並啟動new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){//business的子函數business.sub(i);}}}).start();//因為mian方法本身就佔用一個線程,所以主線程不需要再new Threadfor(int i=1;i<=50;i++){business.main(i);}}} class Business { private boolean bShouldSub = true; //互斥對象為business,即在同一時刻只能訪問sub或main其中一個方法 public synchronized void sub(int i){ //當bShouldSub==false時等待 while(!bShouldSub){ try {//方法使當前線程主動釋放互斥鎖,並進入該互斥鎖的等待隊列。(也就是說,它使當前線程暫停執行,//等待其他線程執行notify()方法或者notifyall()方法後再繼續執行本線程。)this.wait();} catch (InterruptedException e) {e.printStackTrace();} } for(int j=1;j<=10;j++){System.out.println("sub thread sequence of " + j + ",loop of " + i); } bShouldSub = false; //this代表什嗎?--代表Business //喚醒下一個線程 //喚醒在此對象監視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程。 //選擇是任意性的,並在對實現做出決定時發生。 this.notify(); } public synchronized void main(int i){ //當bShouldSub==true時等待 while(bShouldSub){ try {this.wait();} catch (InterruptedException e) {e.printStackTrace();} }for(int j=1;j<=100;j++){System.out.println("main thread sequence of " + j + ",loop of " + i);}bShouldSub = true;this.notify(); } }
列印結果:
總結:
wait()和notify()方法要求在調用時線程已經獲得了對象的鎖,因此對這兩個方法的調用需要放在synchronized方法或synchronized塊中。synchronized保證了main和sub兩個方法在同一時刻只能有一個在執行,那麼bShouldSub值就是在判斷該哪個方法執行。
執行過程可能為:sub()方法先執行(當然也可能是main方法先執行,只是bShouldSub==true,則會的wait),bShouldSub==true,執行for迴圈,之後設定bShouldSub=false,並喚醒等待線程,這時可能還是執行sub()方法(被喚醒的線程並沒有什麼優先權,也沒有什麼劣勢,對象的下一個線程還是需要通過一般性的競爭),但此時bShouldSub==false,故執行while語句,wait,然後main()方法執行。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
JAVA 並發編程-傳統線程同步通訊技術(四)