【Java】異步回調(diào)轉(zhuǎn)為同步返回

java lock condition sync callback

【Spring Boot】一個注解實現(xiàn)下載接口

介紹

大家看完標題是不是覺得就是普通的Future介紹阀坏,但如果我說這里的異步回調(diào)是指從外部調(diào)用服務(wù)的接口來回調(diào),是不是實現(xiàn)同步就比較麻煩了

先給大家舉個例子笆檀,對于我們現(xiàn)在物聯(lián)網(wǎng)方向的開發(fā)忌堂,或多或少都會接觸到物理設(shè)備的對接,甚至需要對設(shè)備進行控制等操作

但是有很大一部分設(shè)備是不會同步返回結(jié)果的酗洒,而是另外上報一條數(shù)據(jù)士修,這就非常難受了

對于前端頁面的用戶來說枷遂,在下發(fā)了一條命令之后,會更希望能直接得到命令響應(yīng)結(jié)果棋嘲,到底是成功還是失敗

但是由于設(shè)備不會同步返回酒唉,就導致用戶需要切換到其他頁面去看設(shè)備響應(yīng)是否成功

在最開始,因為沒有更好的辦法封字,所以我們預(yù)估了從命令下發(fā)一直到接收到數(shù)據(jù)上報的時間間隔黔州,然后用Thread.sleep來阻塞線程,不斷查詢是否上報了結(jié)果

可想而知阔籽,這種方式只能說是非常愚蠢流妻,因為非常不好控制,如果等待時間設(shè)置的太短則可能導致大量請求返回不了結(jié)果笆制,如果等待時間設(shè)置的太長則對于用戶的體驗就非常差

于是我就想有沒有一種方式绅这,能夠在命令下發(fā)后就阻塞線程,直到數(shù)據(jù)上報再喚醒在辆,這樣就能非常精確的控制等待時間

所以我就寫了一個工具來實現(xiàn)這樣的功能

我們先來看看怎么使用吧

@RestController
@RequestMapping("/concept-sync-waiting")
public class SyncWaitingController {

    /**
     * 新建一個 {@link SyncWaitingConcept} 對象
     * 也可以直接在 Spring 容器中注入一個全局使用
     */
    private final SyncWaitingConcept concept = new ConditionSyncWaitingConcept();

    /**
     * 下發(fā)命令证薇,阻塞線程直到數(shù)據(jù)上報或超時
     *
     * @param key 每條命令唯一的id
     * @return 設(shè)備上報的數(shù)據(jù)
     */
    @RequestMapping("/send")
    public String send(@RequestParam String key) {
        try {
            return concept.waitSync(key, new SyncCaller() {
                @Override
                public void call(Object k) {
                    //在這里下發(fā)命令
                }
            }, 5000);
        } catch (SyncWaitingTimeoutException e) {
            return "下發(fā)命令超時";
        }
    }

    /**
     * 接收設(shè)備上報的數(shù)據(jù),喚醒下發(fā)命令的線程
     *
     * @param key   一般需要從上報數(shù)據(jù)中附帶命令id
     * @param value 上報數(shù)據(jù)
     */
    @RequestMapping("/receive")
    public void receive(@RequestParam String key, @RequestParam String value) {
        concept.notifyAsync(key, value);
    }
}

首先創(chuàng)建一個SyncWaitingConcept對象匆篓,默認實現(xiàn)了ConditionSyncWaitingConcept

SyncWaitingConcept concept = new ConditionSyncWaitingConcept();

然后調(diào)用waitSync方法浑度,并阻塞當前線程

需要傳入key作為該次調(diào)用的標識(唯一id),SyncCaller作為觸發(fā)業(yè)務(wù)邏輯調(diào)用的接口鸦概,waitingTime作為等待時間限制(小于等于0時則無限等待)

Object value = concept.waitSync(key, new SyncCaller() {
            @Override
            public void call(Object k) {
                //自己的業(yè)務(wù)邏輯箩张,并附帶上key
            }
        }, 5000);

最后當接收到異步返回的數(shù)據(jù)時,調(diào)用notifyAsync方法喚醒之前阻塞的線程即可得到接收到的數(shù)據(jù)

需要傳入key一般在返回數(shù)據(jù)中附帶回來窗市,value作為接收到的數(shù)據(jù)

concept.notifyAsync(key, value);

是不是還是挺方便的先慷,只要兩個簡單的方法就能阻塞和喚醒線程

如果大家有興趣,Github上的介紹更加詳細咨察,還包括各種高級用法以及整體架構(gòu)

思路

核心思路其實很簡單论熙,就是用Condition來控制線程的阻塞和喚醒

await方法可以阻塞當前的線程,進入等待隊列摄狱,signalAll方法可以喚醒隊列中的所有線程

我把key和對應(yīng)的Condition緩存在一個Map中脓诡,當我們調(diào)用waitSync方法時

  • 先通過key查找是否存在等待中的Condition
  • 如果已經(jīng)存在炸庞,則調(diào)用await讓當前線程排隊阻塞
  • 如果不存在醉锄,則調(diào)用回調(diào)接口中的業(yè)務(wù)邏輯
  • 然后調(diào)用await讓阻塞當前線程
  • 接收數(shù)據(jù),根據(jù)key獲得對應(yīng)的Condition
  • 設(shè)置key對應(yīng)的返回值并調(diào)用signalAll喚醒線程
  • 返回key得到的值
  • 之前直接阻塞的線程也被喚醒并繼續(xù)嘗試執(zhí)行
sync_waiting_process.jpg

結(jié)束

基本上的內(nèi)容就是這樣啦

大家有興趣的話可以捧個場篮条,之后也會慢慢更新其他的庫


其他的文章

【Spring Boot】一個注解實現(xiàn)下載接口

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刊愚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子踩验,更是在濱河造成了極大的恐慌鸥诽,老刑警劉巖商玫,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異牡借,居然都是意外死亡拳昌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門钠龙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炬藤,“玉大人,你說我怎么就攤上這事碴里∩蚩螅” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵咬腋,是天一觀的道長羹膳。 經(jīng)常有香客問我,道長根竿,這世上最難降的妖魔是什么陵像? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮寇壳,結(jié)果婚禮上醒颖,老公的妹妹穿的比我還像新娘。我一直安慰自己壳炎,他們只是感情好泞歉,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冕广,像睡著了一般疏日。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上撒汉,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天沟优,我揣著相機與錄音,去河邊找鬼睬辐。 笑死挠阁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的溯饵。 我是一名探鬼主播侵俗,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丰刊!你這毒婦竟也來了隘谣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寻歧,沒想到半個月后掌栅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡码泛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年猾封,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片噪珊。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晌缘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痢站,到底是詐尸還是另有隱情磷箕,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布瑟押,位于F島的核電站搀捷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏多望。R本人自食惡果不足惜嫩舟,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怀偷。 院中可真熱鬧家厌,春花似錦、人聲如沸椎工。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽维蒙。三九已至掰吕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颅痊,已是汗流浹背殖熟。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斑响,地道東北人菱属。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像舰罚,于是被迫代替她去往敵國和親纽门。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容