1. 程式人生 > >Java執行緒的等待/通知(wait/notify)機制詳解

Java執行緒的等待/通知(wait/notify)機制詳解

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 flagtrue,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秒,輸出結果是否有變?答案是有的,那就是第三行和第四行輸出會顛倒位置(行位的時分秒時間暫不考慮)。