一.查看APIthis
sleep是Thread類的方法,致使此線程暫停執行指定時間,給其餘線程執行機會,可是依然保持着監控狀態,過了指定時間會自動恢復,調用sleep方法不會釋放鎖對象。spa
當調用sleep方法後,當前線程進入阻塞狀態。目的是讓出CPU給其餘線程運行的機會。可是因爲sleep方法不會釋放鎖對象,因此在一個同步代碼塊中調用這個方法後,線程雖然休眠了,但其餘線程沒法訪問它的鎖對象。這是由於sleep方法擁有CPU的執行權,它能夠自動醒來無需喚醒。而當sleep()結束指定休眠時間後,這個線程不必定當即執行,由於此時其餘線程可能正在運行。線程
wait方法是Object類裏的方法,當一個線程執行到wait()方法時,它就進入到一個和該對象相關的等待池中,同時釋放了鎖對象,等待期間能夠調用裏面的同步方法,其餘線程能夠訪問,等待時不擁有CPU的執行權,不然其餘線程沒法獲取執行權。當一個線程執行了wait方法後,必須調用notify或者notifyAll方法才能喚醒,並且是隨機喚醒,如果被其餘線程搶到了CPU執行權,該線程會繼續進入等待狀態。因爲鎖對象能夠時任意對象,因此wait方法必須定義在Object類中,由於Obeject類是全部類的基類。code
二.是否能夠傳入參數對象
sleep()方法必須傳入參數,參數就是休眠時間,時間到了就會自動醒來。blog
wait()方法能夠傳入參數也能夠不傳入參數,傳入參數就是在參數結束的時間後開始等待,不穿如參數就是直接等待。進程
三.是否須要捕獲異常資源
sleep方法必需要捕獲異常,而wait方法不須要捕獲異常。sleep方法屬於Thread類中方法,表示讓一個線程進入睡眠狀態,等待必定的時間以後,自動醒來進入到可運行狀態,不會立刻進入運行狀態,由於線程調度機制恢復線程的運行也須要時間,一個線程對象調用了sleep方法以後,並不會釋放他所持有的全部對象鎖,因此也就不會影響其餘進程對象的運行。但在sleep的過程當中過程當中有可能被其餘對象調用它的interrupt(),產生InterruptedException異常,若是你的程序不捕獲這個異常,線程就會異常終止,進入TERMINATED狀態,若是你的程序捕獲了這個異常,那麼程序就會繼續執行catch語句塊(可能還有finally語句塊)以及之後的代碼。同步
wait屬於Object的成員方法,一旦一個對象調用了wait方法,必需要採用notify()和notifyAll()方法喚醒該進程;若是線程擁有某個或某些對象的同步鎖,那麼在調用了wait()後,這個線程就會釋放它持有的全部同步資源,而不限於這個被調用了wait()方法的對象。wait()方法也一樣會在wait的過程當中有可能被其餘對象調用interrupt()方法而產生。it
四.做用範圍
wait、notify和notifyAll方法只能在同步方法或者同步代碼塊中使用,而sleep方法能夠在任何地方使用。可是注意sleep是靜態方法,也就是說它只對當前對象有效。經過對象名.sleep()想讓該對象線程進入休眠是無效的,它只會讓當前線程進入休眠。
五.調用者的區別
首先爲何wait、notify和notifyAll方法要和synchronized關鍵字一塊兒使用?
由於wait方法是使一個線程進入等待狀態,而且釋放其所持有的鎖對象,notify方法是通知等待該鎖對象的線程從新得到鎖對象,然而若是沒有得到鎖對象,wait方法和notify方法都是沒有意義的,所以必須先得到鎖對象再對鎖對象進行進一步操做因而纔要把wait方法和notify方法寫到同步方法和同步代碼塊中了。
由此可知,wait和notify、notifyAll方法是由肯定的對象即鎖對象來調用的,鎖對象就像一個傳話的人,他對某個線程說停下來等待,而後對另外一個線程說你能夠執行了(實質上是被捕獲了),這一過程是線程通訊。sleep方法是讓某個線程暫停運行一段時間,其控制範圍是由當前線程決定,運行的主動權是由當前線程來控制(擁有CPU的執行權)。
其實二者的區別都是讓線程暫停運行一段時間,但本質的區別一個是線程的運行狀態控制,一個是線程間的通訊。
六.wait方法(線程通訊)的一些注意事項
例如如下代碼:
當線程print1得到了鎖對象(this)後進行判斷,若是不知足條件(flag == 1)沒法繼續執行下面的代碼,因而進入wait狀態。在另外一個線程print3中,因爲改變了flag,使得線程print1的判斷條件知足了,線程print1就會被喚醒。
class Printer { private int flag = 1; public void print1() throws Exception { synchronized(this) { while(flag != 1) { this.wait(); } System.out.print("1"); System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.println(); flag = 2; this.notifyAll(); } } public void print2() throws Exception { synchronized(this) { while(flag != 2) { this.wait(); } System.out.print("5"); System.out.print("6"); System.out.print("7"); System.out.print("8"); System.out.println(); flag = 3; this.notifyAll(); } } public void print3() throws Exception { synchronized(this) { while(flag != 3) { this.wait(); } System.out.print("A"); System.out.print("B"); System.out.print("C"); System.out.print("D"); System.out.println(); flag = 1; this.notifyAll(); } } }
注意事項:
1.調用wait方法和notify、notifyAll方法前必須得到對象鎖,也就是必須寫在synchronized(鎖對象){......}代碼塊中。
2.當線程print1調用了wait方法後就釋放了對象鎖,不然其餘線程沒法得到對象鎖,也就沒法喚醒線程print1。
3.當this.wait()方法返回後,線程必須再次得到對象鎖後才能繼續執行。
4.若是另外兩個線程都在wait,則正在執行的線程調用notify方法只能喚醒一個正在wait的線程(公平競爭,由JVM決定)。
5.當使用notifyAll方法後,全部wait狀態的線程都會被喚醒,可是隻有一個線程能得到鎖對象,必須執行完while(condition){this.wait();}後才能得到對象鎖。其他的須要等待該得到對象鎖的線程執行完釋放對象鎖後才能繼續執行。
6.當某個線程調用notifyAll方法後,雖然其餘線程被喚醒了,可是該線程依然持有着對象鎖,必須等該同步代碼塊執行完(右大括號結束)後纔算正式釋放了鎖對象,另外兩個線程纔有機會執行。