先設想一個場景,你中午喫飯,不知道喫什麼好,想着去食堂喫呢還是點外賣,但是因爲公司願意食堂不一定每次都開門,於是你跟同事說,這樣吧你去食堂,如果開門了你告訴我我就過去,如果沒有開門我就點外賣。
這就是一個等待回調問題,你做一個事件A,中間 需要等待事件B的回調結果,纔可以繼續下一步。
開發中這樣的場景很多吧。那麼如何解決能?
別告訴我,寫一個死循環,while() 然後 sleep 然後 break
這樣肯定不對的。一個是 你時間上有時間差,也併發的情況下會造成死循環。
那麼如何優雅解決回調等待問題? 直接自己跑一下
上代碼:
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Predicate; public class GuardedObject<T> { //受保護的對象 T obj; final Lock lock = new ReentrantLock(); final Condition done = lock.newCondition(); final int timeout = 2; //保存所有GuardedObject final static Map<Object, GuardedObject> goMap = new ConcurrentHashMap<>(); //靜態方法創建GuardedObject static <K> GuardedObject create(K key) { GuardedObject go = new GuardedObject(); goMap.put(key, go); return go; } static <K, T> void fireEvent(K key, T obj) { GuardedObject go = goMap.remove(key); if (go != null) { go.onChanged(obj); } } //獲取受保護對象 T get(Predicate<T> p) { lock.lock(); try { //MESA管程推薦寫法 while (!p.test(obj)) { done.await(timeout, TimeUnit.SECONDS); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } //返回非空的受保護對象 return obj; } //事件通知方法 void onChanged(T obj) { lock.lock(); try { this.obj = obj; done.signalAll(); } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { int id = 123;//識別id這裏寫死,正常是一個隨機生成器 String sendMessage = "Hello world !!!"; System.out.println("消息開始發送》》》 id :" + id + " 報文:" + sendMessage); //模擬外部系統 new Thread(()->{ outSystem(id,sendMessage); }).start(); GuardedObject<String> go = GuardedObject.create(id);//創建等待GuardedObject String result = go.get(t -> t != null);//開始 等待回調 System.out.println("接收到的回調信息:" + result); } /** * 外部回調 * * @param id * @param str */ public static void onMessage(int id, String str) { GuardedObject.fireEvent(id, str); } public static void outSystem(int id, String sendMessage) { //外部調用這裏假設另一個系統處理請求 System.out.println("接收到消息" + sendMessage + " 接收到標識id :" + id); //開始處理... try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } //處理完成回調 String callBack = "已收到消息:" + sendMessage + " "; onMessage(id, callBack);//開始回調 } }