Java的等待/通知 機(jī)制式镐,舉例來說就是反镇,線程A,拿到了對象object的鎖娘汞,并且調(diào)用了object的wait()方法歹茶,同時釋放了鎖,然后進(jìn)入WAITTING狀態(tài)辆亏。線程B同樣前提是拿到了object的鎖,然后調(diào)用了notify()或notifyAll()方法鳖目,線程A收到了線程B的通知后扮叨,從wait()方法上返回,繼續(xù)執(zhí)行它的操作领迈。
Java的相關(guān) 等待/通知 相關(guān)方法是所有對象都有的方法彻磁,因為這些方法被定義在超類Object
中。具體的方法有notify()
狸捅,notifyAll()
衷蜓,wait()
等。
具體的解釋說明為:
- notify():該線程獲取到了對象的鎖尘喝,通知此線程磁浇,讓它從wait()方法返回
- notifyAll():與notify()類似,不過是通知所有等待的線程
- wait():一個線程如果調(diào)用了這個方法朽褪,線程將進(jìn)入WAITTING狀態(tài)置吓,并且會將鎖釋放
具體例子可以參考:
/**
* @author gzd
* @date 2018/4/23 15:52
* @desc 線程的 等待/通知 機(jī)制
*/
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衍锚,開始繼續(xù)工作" + 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() + " 持有鎖,發(fā)出通知" + 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();
}
}
}
}
}
}
上面程序的打印結(jié)果為:
Thread[WaitThread,5,main]線程狀態(tài):RUNNABLE flag是true,wait嗤堰。戴质。16:46:39
Thread[NotifyThread,5,main]線程狀態(tài):RUNNABLE持有鎖,發(fā)出通知16:46:40
Thread[NotifyThread,5,main]線程狀態(tài):RUNNABLE 再次拿到鎖. sleep @ 16:46:45
Thread[WaitThread,5,main]線程狀態(tài):RUNNABLE flag是false踢匣,開始繼續(xù)工作16:46:50
根據(jù)程序可以看到告匠,大致的過程就是:WaitThread拿到lock對象的鎖,然后根據(jù)flag標(biāo)記离唬,自己調(diào)用了wait()方法凫海,從而釋放鎖并進(jìn)入WAITTING狀態(tài)。NotifyThread此時獲取了lock對象的鎖男娄,然后進(jìn)行notify操作,此時WaitThread并沒有從WAITTING中被喚醒,因為WaitThread還沒有釋放鎖模闲。那么試想一下在NotifyThread的第二個鎖前建瘫,增加一個sleep 3秒,輸出結(jié)果是否有變尸折?答案是有的啰脚,那就是第三行和第四行輸出會顛倒位置(行位的時分秒時間暫不考慮)。