激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解Java中CountDownLatch異步轉同步工具類

詳解Java中CountDownLatch異步轉同步工具類

2021-09-22 00:57lingzhi_ying Java教程

今天給大家帶來的是關于Java的相關知識,文章圍繞著CountDownLatch異步轉同步工具類展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下

使用場景

由于公司業務需求,需要對接socket、MQTT等消息隊列。
眾所周知 socket 是雙向通信,socket的回復是人為定義的,客戶端推送消息給服務端,服務端的回復是兩條線。無法像http請求有回復。
下發指令給硬件時,需要校驗此次數據下發是否成功。
用戶體驗而言,點擊按鈕就要知道此次的下發成功或失敗。

詳解Java中CountDownLatch異步轉同步工具類

如上圖模型,

第一種方案使用Tread.sleep
優點:占用資源小,放棄當前cpu資源
缺點: 回復速度快,休眠時間過長,仍然需要等待休眠結束才能返回,響應速度是固定的,無法及時響應第二種方案使用CountDownLatch

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package com.lzy.demo.delay;
 
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
 
public class CountDownLatchPool {
 
    //countDonw池
    private final static Map<Integer, CountDownLatch> countDownLatchMap = new ConcurrentHashMap<>();
    //延遲隊列
    private final static DelayQueue<MessageDelayQueueUtil> delayQueue = new DelayQueue<>();
 
    private volatile static boolean flag =false;
    //單線程池
    private final static ExecutorService t = new ThreadPoolExecutor(1, 1,
        0L, TimeUnit.MILLISECONDS,
        new ArrayBlockingQueue<>(1));
 
    public static void addCountDownLatch(Integer messageId) {
        CountDownLatch countDownLatch = countDownLatchMap.putIfAbsent(messageId,new CountDownLatch(1) );
        if(countDownLatch == null){
            countDownLatch = countDownLatchMap.get(messageId);
        }
        try {
            addDelayQueue(messageId);
            countDownLatch.await(3L, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("阻塞等待結束~~~~~~");
    }
 
    public static void removeCountDownLatch(Integer messageId){
        CountDownLatch countDownLatch = countDownLatchMap.get(messageId);
        if(countDownLatch == null)
            return;
        countDownLatch.countDown();
        countDownLatchMap.remove(messageId);
        System.out.println("清除Map數據"+countDownLatchMap);
    }
 
    private static void addDelayQueue(Integer messageId){
        delayQueue.add(new MessageDelayQueueUtil(messageId));
        clearMessageId();
    }
 
    private static void clearMessageId(){
        synchronized (CountDownLatchPool.class){
            if(flag){
                return;
            }
            flag = true;
        }
        t.execute(()->{
            while (delayQueue.size() > 0){
                System.out.println("進入線程并開始執行");
                try {
                    MessageDelayQueueUtil take = delayQueue.take();
                    Integer messageId1 = take.getMessageId();
                    removeCountDownLatch(messageId1);
                    System.out.println("清除隊列數據"+messageId1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            flag = false;
            System.out.println("結束end----");
        });
    }
 
    public static void main(String[] args) throws InterruptedException {
        /*
        測試超時清空map
        new Thread(()->addCountDownLatch(1)).start();
        new Thread(()->addCountDownLatch(2)).start();
        new Thread(()->addCountDownLatch(3)).start();
        */
        //提前創建線程,清空countdown
        new Thread(()->{
            try {
                Thread.sleep(500L);
                removeCountDownLatch(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        //開始阻塞
        addCountDownLatch(1);
        //通過調整上面的sleep我們發現阻塞市場取決于countDownLatch.countDown()執行時間
        System.out.println("阻塞結束----");
    }
}
class MessageDelayQueueUtil implements Delayed {
 
    private Integer messageId;
    private long avaibleTime;
 
    public Integer getMessageId() {
        return messageId;
    }
 
    public void setMessageId(Integer messageId) {
        this.messageId = messageId;
    }
 
    public long getAvaibleTime() {
        return avaibleTime;
    }
 
    public void setAvaibleTime(long avaibleTime) {
        this.avaibleTime = avaibleTime;
    }
 
    public MessageDelayQueueUtil(Integer messageId){
        this.messageId = messageId;
        //avaibleTime = 當前時間+ delayTime
        //重試3次,每次3秒+1秒的延遲
        this.avaibleTime=3000*3+1000 + System.currentTimeMillis();
    }
 
    @Override
    public long getDelay(TimeUnit unit) {
        long diffTime= avaibleTime- System.currentTimeMillis();
        return unit.convert(diffTime,TimeUnit.MILLISECONDS);
    }
 
    @Override
    public int compareTo(Delayed o) {
        //compareTo用在DelayedUser的排序
        return (int)(this.avaibleTime - ((MessageDelayQueueUtil) o).getAvaibleTime());
    }
}

由于socket并不確定每次都會有數據返回,所以map的數據會越來越大,最終導致內存溢出
需定時清除map內的無效數據。
可以使用DelayedQuene延遲隊列來處理,相當于給對象添加一個過期時間

使用方法 addCountDownLatch 等待消息,異步回調消息清空removeCountDownLatch

到此這篇關于詳解Java中CountDownLatch異步轉同步工具類的文章就介紹到這了,更多相關CountDownLatch異步轉同步工具類內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/qq_37256345/article/details/117808156

延伸 · 閱讀

精彩推薦
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7472021-02-04
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
主站蜘蛛池模板: 黄色av.com| 亚洲一区二区三区在线看 | 素人视频在线观看免费 | 亚洲电影在线观看高清免费 | 二区三区偷拍浴室洗澡视频 | 羞羞的视频免费在线观看 | 日本va在线观看 | 天天看成人免费毛片视频 | 嗯~啊~用力~高h | 欧美a黄 | 中文字幕涩涩久久乱小说 | 亚洲精品午夜视频 | 成人免费观看在线视频 | 羞羞色院91精品网站 | 羞羞漫画无遮挡观看 | 一级一级一级毛片 | 视频一区国产精品 | 久久亚洲成人网 | 免费国产一区二区视频 | 日韩精品一区二区亚洲 | 成人做爰www免费看 成人午夜视频免费看 | 国产精品免费成人 | 国产精品久久久久久模特 | 久久国产精品免费视频 | 久久精品视频在线免费观看 | 91 免费看片 | 亚洲成人入口 | 性片久久 | 免费高清一级欧美片在线观看 | 国产一级做a爰片在线看 | 欧美黄 片免费观看 | 毛片在线视频免费观看 | 成人在线精品视频 | 九九热在线视频免费观看 | 中文字幕在线网 | 欧美一级视屏 | 黄色成人小视频 | 免费国产羞羞网站视频 | 在线成人www免费观看视频 | 九九热免费在线观看 | 一级做a爱片性色毛片高清 日本一区二区在线看 |