多線程-線程之間的通信

自我總結核心內容:線程之間的通信是通過具體對象來實現信息的交互的。而對象有wait和notafy方法,當一個線程調用了一個對象的wait方法,那麼這個線程就處於暫停狀態,如果另外一個線程調用了第一個線程對象的notify,那麼含義就是說,我這個對象可以用了,那麼所以調用我這個對象的線程,你們都可以繼續執行你們的功能。但是需要注意,在線程waiti方法結束的時候,他必須要獲得這個對象的鎖,纔可以退出wait方法。

對於wait,Notify,notifyall方法的總結:

共同點:這三個方法都必須在同步塊裏面執行,之所以這樣設計,個人的理解是一個對象的狀態不應該同時又多個線程在同時對他進行改變,必定是同一時刻只能有一個現成來處理,因此,如果線程之間的通信,對於對象來說,如果這個對象想讓調用它的線程都先暫停一下,那麼就把wati方法同步塊裏面,暫停之後,其他線程該做什麼就做什麼,該喚醒的喚醒,該做其他處理的就做其他處理。因此,不難可以總結出來,想讓一些線程暫時停下,可以通過交互的對象來控制,也就是說,我這個對象調用wati了,那麼你們一個個調用的線程,都按着順序暫停下來。然後等着其他線程來調用我的notify喚醒方法,來喚醒你們,這樣你們纔可以繼續運行,這就是線程之間的通信,當然,線程之間的通信,通過對象來實現,也是可以理解的,因爲在面向對象的設計語言中,彼此之間事物的交互,也就是通過對象來完成。

下面對幾個方法分別講解:

第一:wait 我們知道,這幾個方法,都在同步塊裏面執行,一旦一個線程執行到一個對象的wait方法,那麼這個線程就會被暫停,也就是wait下面的方法不會執行了。如以下代碼:

public class MonitorObject{
}

public class MyWaitNotify{

  MonitorObject myMonitorObject = new MonitorObject();

  public void doWait(){
    synchronized(myMonitorObject){
      try{
        myMonitorObject.wait();
	System.out.println("wait is end");
      } catch(InterruptedException e){...}
    }
  }

  public void doNotify(){
    synchronized(myMonitorObject){
      myMonitorObject.notify();
    }
  }
}
也就是System.out.println("wait is end");這個方法不會執行,因爲當前線程已經暫停,但是問題來了,從代碼中發現,這個同步塊synchronized並沒有結束啊,既然同步塊沒有結束,那麼這個對象的鎖就沒辦法釋放,而且一個對象也就一個同步鎖,但是喚醒方法,也必須在當前對象的同步塊裏面執行,這樣來推算,其他的現成都沒法執行dotify方法了。

但是,java虛擬機並不會因此在違前面的所有涉及,規定在調用一個對象調用wait方法時候,第一:他能讓當前調用的線程暫停;第二:他能讓所有調用這個方法的線程釋放了這個對象的鎖,也就是說釋放了所有持有這個對象的鎖,等到他被喚醒,退出wati的時候,再重新獲取這個對象鎖。

所以這樣的一種機制,其他的線程就可以執行喚醒操作了。

第二:notify 上面已經講過,對象調用這個方法,他會喚醒引用當前對象的線程中的某一個線程,是他從暫停狀態變成運行狀態,當然是隨機的

第三: NOtifyaLL  從字面上不能理解,他就是喚醒所有引用當前對象鎖的現成,是他們變成運行狀態、


第二部分:信號丟失

由於線程的執行時隨機的,假設有四個線程調用對象的wati方法,也就是讓這四個線程先休息一下,然後第五個線程可能需要處理一些東西,然後然第五個現成調用這個對象的Notify把你們都喚醒。理想中的設計是這樣的,但是有可能第五個線程先執行了,當然此時並沒線程執行wait方法,所以他雖然執行了喚醒操作,但是並沒有喚醒任何線程,但是,對他來說無所謂,他已經完成了自己的任務了。可是,問題來了,由於缺少了喚醒操作的線程,所以前面四個線程調用wait的時候,都可能永遠的處於等待狀態,而沒有人喚醒。

基於以上一種現象,我們事先方式是,如果第一個喚醒線程先執行了,我們可以設計一個信號量,表示已經線程已經執行過喚醒操作了,如以下代碼:

public class MyWaitNotify2{

  MonitorObject myMonitorObject = new MonitorObject();
  boolean wasSignalled = false;

  public void doWait(){
    synchronized(myMonitorObject){
      if(!wasSignalled){
        try{
          myMonitorObject.wait();
         } catch(InterruptedException e){...}
      }
      //clear signal and continue running.
      wasSignalled = false;
    }
  }

  public void doNotify(){
    synchronized(myMonitorObject){
      wasSignalled = true;
      myMonitorObject.notify();
    }
  }
}
當第五個喚醒線程執行了Notify方法,他會把變量設置爲true,那麼這種情況,第一個wait線程執行的時候,他就不會執行wait裏面的If語句,他會繼續向下執行,然後把變量設爲false,這樣,其他的線程再來執行的時候,就全部都執行IF語句,最終暫停下來。如果wait方法線程塊後面有很多的代碼需要執行,這樣就可以保證其他線程暫停,確定是,第一個執行wait的方法,依然會執行後面的重要代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章