Java執行緒的等待/通知(wait/notify)機制詳解
阿新 • • 發佈:2019-02-07
Java的等待/通知 機制,舉例來說就是,執行緒A,拿到了物件object的鎖,並且呼叫了object的wait()方法,同時釋放了鎖,然後進入WAITTING狀態。執行緒B同樣前提是拿到了object的鎖,然後呼叫了notify()或notifyAll()方法,執行緒A收到了執行緒B的通知後,從wait()方法上返回,繼續執行它的操作。
Java的相關 等待/通知 相關方法是所有物件都有的方法,因為這些方法被定義在超類Object
中。具體的方法有notify()
,notifyAll()
,wait()
等。
具體的解釋說明為:
- notify():該執行緒獲取到了物件的鎖,通知此執行緒,讓它從wait()方法返回
- notifyAll():與notify()類似,不過是通知所有等待的執行緒
- wait():一個執行緒如果呼叫了這個方法,執行緒將進入WAITTING狀態,並且會將鎖釋放
具體例子可以參考:
/**
* @author gzd
* @date 2018/4/23 15:52
* @desc 執行緒的 等待/通知 機制
*/
public class WaitAndNotify {
private static boolean flag = true;
private static Object lock = new Object();
public static void main(String[] args) {
Thread waitThread = new Thread(new Wait(), "WaitThread");
waitThread.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread notifyThread = new Thread(new Notify(), "NotifyThread");
notifyThread.start();
}
private static class Wait implements Runnable {
@Override
public void run() {
synchronized (lock) {
while (flag) {
System.out.println(Thread.currentThread() + " flag是true,wait。。" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread() + " flag是false,開始繼續工作" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
private static class Notify implements Runnable {
@Override
public void run() {
synchronized (lock){
System.out.println(Thread.currentThread() + " 持有鎖,發出通知" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再次加鎖
synchronized (lock) {
System.out.println(Thread.currentThread() + " 再次拿到鎖. sleep @ " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
上面程式的列印結果為:
Thread[WaitThread,5,main]執行緒狀態:RUNNABLE flag是true,wait。。16:46:39
Thread[NotifyThread,5,main]執行緒狀態:RUNNABLE持有鎖,發出通知16:46:40
Thread[NotifyThread,5,main]執行緒狀態:RUNNABLE 再次拿到鎖. sleep @ 16:46:45
Thread[WaitThread,5,main]執行緒狀態:RUNNABLE flag是false,開始繼續工作16:46:50
根據程式可以看到,大致的過程就是:WaitThread拿到lock物件的鎖,然後根據flag標記,自己呼叫了wait()方法,從而釋放鎖並進入WAITTING狀態。NotifyThread此時獲取了lock物件的鎖,然後進行notify操作,此時WaitThread並沒有從WAITTING中被喚醒,因為WaitThread還沒有釋放鎖。那麼試想一下在NotifyThread的第二個鎖前,增加一個sleep 3秒,輸出結果是否有變?答案是有的,那就是第三行和第四行輸出會顛倒位置(行位的時分秒時間暫不考慮)。