sleep(),wait(),yield()和join()方法的區別
sleep()
sleep()方法需要指定等待的時間,它可以讓當前正在執行的執行緒在指定的時間內暫停執行,進入阻塞狀態,該方法既可以讓其他同優先順序或者高優先順序的執行緒得到執行的機會,也可以讓低優先順序的執行緒得到執行機會。但是sleep()方法不會釋放“鎖標誌”,也就是說如果有synchronized同步塊,其他執行緒仍然不能訪問共享資料。
wait()
wait()方法需要和notify()及notifyAll()兩個方法一起介紹,這三個方法用於協調多個執行緒對共享資料的存取,所以必須在synchronized語句塊內使用,也就是說,呼叫wait(),notify()和notifyAll()的任務在呼叫這些方法前必須擁有物件的鎖。注意,它們都是Object類的方法,而不是Thread類的方法。
wait()方法與sleep()方法的不同之處在於,wait()方法會釋放物件的“鎖標誌”。當呼叫某一物件的wait()方法後,會使當前執行緒暫停執行,並將當前執行緒放入物件等待池中,直到呼叫了notify()方法後,將從物件等待池中移出任意一個執行緒並放入鎖標誌等待池中,只有鎖標誌等待池中的執行緒可以獲取鎖標誌,它們隨時準備爭奪鎖的擁有權。當呼叫了某個物件的notifyAll()方法,會將物件等待池中的所有執行緒都移動到該物件的鎖標誌等待池。
除了使用notify()和notifyAll()方法,還可以使用帶毫秒引數的wait(long timeout)方法,效果是在延遲timeout毫秒後,被暫停的執行緒將被恢復到鎖標誌等待池。
此外,wait(),notify()及notifyAll()只能在synchronized語句中使用,但是如果使用的是ReenTrantLock實現同步,該如何達到這三個方法的效果呢?解決方法是使用ReenTrantLock.newCondition()獲取一個Condition類物件,然後Condition的await(),signal()以及signalAll()分別對應上面的三個方法。
yield()
yield()方法和sleep()方法類似,也不會釋放“鎖標誌”,區別在於,它沒有引數,即yield()方法只是使當前執行緒重新回到可執行狀態,所以執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行,另外yield()方法只能使同優先順序或者高優先順序的執行緒得到執行機會,這也和sleep()方法不同。
join()
join()方法會使當前執行緒等待呼叫join()方法的執行緒結束後才能繼續執行,例如:
package concurrent;
public class TestJoin {
public static void main (String[] args) {
Thread thread = new Thread(new JoinDemo());
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("主執行緒第" + i + "次執行!");
if (i >= 2)
try {
// t1執行緒合併到主執行緒中,主執行緒停止執行過程,轉而執行t1執行緒,直到t1執行完畢後繼續。
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class JoinDemo implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("執行緒1第" + i + "次執行!");
}
}
}
程式執行結果如下: