如何優雅解決回調等待問題

先設想一個場景,你中午喫飯,不知道喫什麼好,想着去食堂喫呢還是點外賣,但是因爲公司願意食堂不一定每次都開門,於是你跟同事說,這樣吧你去食堂,如果開門了你告訴我我就過去,如果沒有開門我就點外賣。

這就是一個等待回調問題,你做一個事件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);//開始回調
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章