首先要明確,wait是Object類的方法,也就是說,所有的對象都有wait方法,而且都是Object中的wait方法因爲wait方法被標爲final無法被重寫,源碼如下:
- 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++,源碼如下:
- public final void wait(long timeout, int nanos) throws InterruptedException {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
- timeout++;
- }
- wait(timeout);
- }
說是爲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異常:
- /**
- * Causes the currently executing thread to sleep (temporarily cease
- * execution) for the specified number of milliseconds, subject to
- * the precision and accuracy of system timers and schedulers. The thread
- * does not lose ownership of any monitors.
- *
- * @param millis
- * the length of time to sleep in milliseconds
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public static native void sleep(long millis) throws InterruptedException;
- /**
- * Causes the currently executing thread to sleep (temporarily cease
- * execution) for the specified number of milliseconds plus the specified
- * number of nanoseconds, subject to the precision and accuracy of system
- * timers and schedulers. The thread does not lose ownership of any
- * monitors.
- *
- * @param millis
- * the length of time to sleep in milliseconds
- *
- * @param nanos
- * {@code 0-999999} additional nanoseconds to sleep
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative, or the value of
- * {@code nanos} is not in the range {@code 0-999999}
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public static void sleep(long millis, int nanos)
- throws InterruptedException {
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
- millis++;
- }
- sleep(millis);
- }
PS:雙參數的sleep與雙參數的wait方法一樣,提供了更加精細(然而並沒有)的時間控制,上面說了就不重複一遍了。
sleep與wait,在非多線程運行條件下的情況是一樣的,都是當前線程讓出執行機會,進入休眠/等待。但是在synchronized中就有一些不一樣了:
1.wait會釋放同步鎖,讓其他線程進入synchronized代碼塊執行。sleep不會釋放鎖,其他線程只能等待在synchronized代碼塊中進入sleep的線程醒後執行完畢才能競爭持有鎖。
2.wait可以被notify/notifyAll等方法喚醒,繼續競爭CPU和鎖。sleep方法只能等待線程睡眠時間到繼續運行。
wait和notify/notifyAll以及sleep的測試代碼:
待補充