等待和通知java
等待和通知的標準範式面試
等待方:express
1:獲取對象的鎖編程
2:在循環中判斷條件是否知足,不知足調用wait方法繼續阻塞,爲啥要要循環中判斷呢?由於該線程被喚醒以後可能條件依舊不知足網絡
3:條件知足,執行業務邏輯併發
通知方:ide
1:獲取對象的鎖測試
2:改變相關條件ui
3:通知全部等待在對象的線程this
都是屬於Object的方法
等待:wait
通知:notify/notifyAll
需求:一個快遞在變動;里程數和地點的時候通知等待的線程處理變動後的請求
測試使用notifyAll喚醒
實體類
package org.dance.day1.wn; /** * 快遞實體類 * * @author ZYGisComputer */ public class Express { public final static String CITY = "ShangHai"; /** * 快遞運輸的里程數 */ private int km; /** * 快遞到達的地點 */ private String site; public Express() { } public Express(int km, String site) { this.km = km; this.site = site; } /** * 變化千米數:而後通知處於wait狀態並須要處理千米數的線程進行業務處理 */ public synchronized void checkKm() { // 變化千米數 this.km = 101; // 所有通知 notifyAll(); } /** * 變化地點:而後通知處於wait狀態並須要處理地點的線程進行業務處理 */ public synchronized void checkSite() { // 變化城市 this.site = "BeiJin"; // 所有通知 notifyAll(); } public synchronized void waitKm() { // 循環等待 while (this.km <= 100) { try { wait(); System.out.println("check km " + Thread.currentThread().getId()); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("the km is " + this.km + ", I will change DB."); } public synchronized void waitSite() { // 循環等待 while (CITY.equals(this.site)) { try { wait(); System.out.println("check site " + Thread.currentThread().getId()); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("the site is " + this.site + ", I will change DB."); } }
測試類
package org.dance.day1.wn; import org.dance.tools.SleepTools; /** * 測試wait notify/notifyAll * @author ZYGisComputer */ public class TestWN { private static Express express = new Express(0,Express.CITY); /** * 檢查里程數變化的線程,不知足一直等待 */ private static class CheckKm extends Thread{ @Override public void run() { express.waitKm(); } } /** * 檢查城市變化的線程,不知足一直等待 */ private static class CheckSite extends Thread{ @Override public void run() { express.waitSite(); } } public static void main(String[] args) { for (int i = 0; i < 3; i++) { new CheckKm().start(); } for (int i = 0; i < 3; i++) { new CheckSite().start(); } SleepTools.second(1); // 修改里程數 express.checkKm(); } }
測試結果:
check site 16 check site 15 check site 14 check km 13 the km is 101, I will change DB. check km 12 the km is 101, I will change DB. check km 11 the km is 101, I will change DB.
測試發現所有的線程所有被喚醒了,而後其中三個等待城市變化的線程再次進入阻塞,另外三個等待里程數變化的執行成功退出阻塞
測試使用notify喚醒
返回結果:
check km 11
the km is 101, I will change DB.
check site 11
由於notify通知任意一個在這個對象上阻塞的線程,若是正好通知到了,等待里程數的,那麼也只有一個被喚醒,其餘兩個繼續阻塞,若是通知到了一個等待城市變化的那麼這個線程將繼續進入阻塞,因此看來,咱們應該儘可能使用notifyAll少用notify,由於可能發生信號丟失的狀況
/** * Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them * is chosen to be awakened. The choice is arbitrary and occurs at * the discretion of the implementation. A thread waits on an object's * monitor by calling one of the {@code wait} methods. * <p> * The awakened thread will not be able to proceed until the current * thread relinquishes the lock on this object. The awakened thread will * compete in the usual manner with any other threads that might be * actively competing to synchronize on this object; for example, the * awakened thread enjoys no reliable privilege or disadvantage in being * the next thread to lock this object. * <p> * This method should only be called by a thread that is the owner * of this object's monitor. A thread becomes the owner of the * object's monitor in one of three ways: * <ul> * <li>By executing a synchronized instance method of that object. * <li>By executing the body of a {@code synchronized} statement * that synchronizes on the object. * <li>For objects of type {@code Class,} by executing a * synchronized static method of that class. * </ul> * <p> * Only one thread at a time can own an object's monitor. * * @throws IllegalMonitorStateException if the current thread is not * the owner of this object's monitor. * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() */ public final native void notify();
在源碼中能夠看到,這個方法是一個 native的
在他的描述中有一段
The choice is arbitrary and occurs at,the discretion of the implementation.
翻譯爲中文
選擇是任意的,發生在,執行的自由裁量權。
因此說notify的喚醒是隨意的,而且信號只發出一次
可是據有人說,在線程進入等待的時候會進入一個等待隊列,notify會喚醒第一個等待的線程
通過在百度上一頓搜索,瀏覽了大量的文章以後
我獲得的結果就是在HotSpot虛擬機當中 notify喚醒的是阻塞線程隊列當中的第一個ObjectWaiter節點,其餘虛擬機不必定.
我以爲這個問題也已當作一個在面試的時候,你問面試官的一個技術性問題
做者:彼岸舞
時間:2020\09\16
內容關於:併發編程
本文來源於網絡,只作技術分享,一律不負任何責任