sleep和wait的區別,以及源碼解讀

首先要明確,wait是Object類的方法,也就是說,所有的對象都有wait方法,而且都是Object中的wait方法因爲wait方法被標爲final無法被重寫,源碼如下:

[java] view plain copy
  1. public final native void wait(long timeout) throws InterruptedException;  

    native關鍵字修飾,表示這個方法使用其他語言實現,又由java由C編寫可得,這個方法做了很可能是C與操作系統級別的交互。拋出InterruptedException,表示線程可能由已經終止的風險。

    Object提供了幾個wait方法:

                    

    最終都調用了我上面貼了源碼的那個方法。這裏wait由兩個參數的方法需要解釋一下,一個long類型參數表示的就是線程等待時間,第二個int類型參數nanos表示納秒,1毫秒=1000微秒=1000000納秒。當參數nanos超過500000時,等待的毫秒值也就是timeout++,源碼如下:

[java] view plain copy
  1. public final void wait(long timeout, int nanos) throws InterruptedException {  
  2.        if (timeout < 0) {  
  3.            throw new IllegalArgumentException("timeout value is negative");  
  4.        }  
  5.   
  6.        if (nanos < 0 || nanos > 999999) {  
  7.            throw new IllegalArgumentException(  
  8.                                "nanosecond timeout value out of range");  
  9.        }  
  10.   
  11.        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {  
  12.            timeout++;  
  13.        }  
  14.   
  15.        wait(timeout);  
  16.    }  

    說是爲wait方法提供了更加精準的時間控制,但是這個也略敷衍了吧。處理方法明白說 - 就是大於半毫秒的+1毫秒,小於半毫秒的直接捨棄。

    說完wait的源碼,看一下停止wait的方法,notify和notifyAll。

    與wait一樣,notify和notifyAll也是Object提供的方法,也是native方法。

    兩者的區別就在這個All上,下面詳細介紹一下:

    1.notify :隨機 (據說與線程優先級有關) 喚醒一個登記集中的等待線程,該線程將從等待集中移除,重新加入對CPU時間片的競爭當中。

    2.notifyAll:喚起所有等待集中的等待線程,所有都加入對CPU時間片的爭奪中,先搶到鎖的先執行。

wait和notify和notifyAll的使用場景:

       已知wait有釋放同步鎖的效果,即當處於synchronized方法中的線程進入wait後,synchronized鎖將會自動被釋放,其他線程可以申請鎖、持有鎖,然後進入這個synchronized方法進行運行。

        notify和notifyAll後並不會返回之前持有的鎖,而是一起開始競爭鎖,誰先競爭到了,誰先執行。


    接下來說一下sleep方法,這個方式是由Thread提供的native方法,與wait一樣,拋出了InterruptedException異常:

[java] view plain copy
  1. /** 
  2.      * Causes the currently executing thread to sleep (temporarily cease 
  3.      * execution) for the specified number of milliseconds, subject to 
  4.      * the precision and accuracy of system timers and schedulers. The thread 
  5.      * does not lose ownership of any monitors. 
  6.      * 
  7.      * @param  millis 
  8.      *         the length of time to sleep in milliseconds 
  9.      * 
  10.      * @throws  IllegalArgumentException 
  11.      *          if the value of {@code millis} is negative 
  12.      * 
  13.      * @throws  InterruptedException 
  14.      *          if any thread has interrupted the current thread. The 
  15.      *          <i>interrupted status</i> of the current thread is 
  16.      *          cleared when this exception is thrown. 
  17.      */  
  18.     public static native void sleep(long millis) throws InterruptedException;  
  19.   
  20.     /** 
  21.      * Causes the currently executing thread to sleep (temporarily cease 
  22.      * execution) for the specified number of milliseconds plus the specified 
  23.      * number of nanoseconds, subject to the precision and accuracy of system 
  24.      * timers and schedulers. The thread does not lose ownership of any 
  25.      * monitors. 
  26.      * 
  27.      * @param  millis 
  28.      *         the length of time to sleep in milliseconds 
  29.      * 
  30.      * @param  nanos 
  31.      *         {@code 0-999999} additional nanoseconds to sleep 
  32.      * 
  33.      * @throws  IllegalArgumentException 
  34.      *          if the value of {@code millis} is negative, or the value of 
  35.      *          {@code nanos} is not in the range {@code 0-999999} 
  36.      * 
  37.      * @throws  InterruptedException 
  38.      *          if any thread has interrupted the current thread. The 
  39.      *          <i>interrupted status</i> of the current thread is 
  40.      *          cleared when this exception is thrown. 
  41.      */  
  42.     public static void sleep(long millis, int nanos)  
  43.     throws InterruptedException {  
  44.         if (millis < 0) {  
  45.             throw new IllegalArgumentException("timeout value is negative");  
  46.         }  
  47.   
  48.         if (nanos < 0 || nanos > 999999) {  
  49.             throw new IllegalArgumentException(  
  50.                                 "nanosecond timeout value out of range");  
  51.         }  
  52.   
  53.         if (nanos >= 500000 || (nanos != 0 && millis == 0)) {  
  54.             millis++;  
  55.         }  
  56.   
  57.         sleep(millis);  
  58.     }  

PS:雙參數的sleep與雙參數的wait方法一樣,提供了更加精細(然而並沒有)的時間控制,上面說了就不重複一遍了。

    sleep與wait,在非多線程運行條件下的情況是一樣的,都是當前線程讓出執行機會,進入休眠/等待。但是在synchronized中就有一些不一樣了:

     1.wait會釋放同步鎖,讓其他線程進入synchronized代碼塊執行。sleep不會釋放鎖,其他線程只能等待在synchronized代碼塊中進入sleep的線程醒後執行完畢才能競爭持有鎖。

     2.wait可以被notify/notifyAll等方法喚醒,繼續競爭CPU和鎖。sleep方法只能等待線程睡眠時間到繼續運行。

     wait和notify/notifyAll以及sleep的測試代碼:

    待補充

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