最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java并發(fā)使用CountDownLatch在生產(chǎn)環(huán)境翻車剖析

 更新時(shí)間:2022年08月10日 10:34:13   作者:叫我小郭_  
這篇文章主要為大家介紹了java并發(fā)使用CountDownLatch在生產(chǎn)環(huán)境翻車的示例剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

大家好,我是小郭,之前分享了CountDownLatch的使用,我們知道用來(lái)控制并發(fā)流程的同步工具,主要的作用是為了等待多個(gè)線程同時(shí)完成任務(wù)后,在進(jìn)行主線程任務(wù)。

萬(wàn)萬(wàn)沒(méi)想到,在生產(chǎn)環(huán)境中竟然翻車了,因?yàn)闆](méi)有考慮到一些場(chǎng)景,導(dǎo)致了CountDownLatch出現(xiàn)了問(wèn)題,接下來(lái)來(lái)分享一下由于CountDownLatch導(dǎo)致的問(wèn)題。

【線程】并發(fā)流程控制的同步工具-CountDownLatch

需求背景

先簡(jiǎn)單介紹下業(yè)務(wù)場(chǎng)景,針對(duì)用戶批量下載的文件進(jìn)行修改上傳

為了提高執(zhí)行的速度,所以在采用線程池去執(zhí)行 下載-修改-上傳 的操作,并在全部執(zhí)行完之后統(tǒng)一提交保存文件地址到數(shù)據(jù)庫(kù),于是加入了CountDownLatch來(lái)進(jìn)行控制。

具體實(shí)現(xiàn)

根據(jù)服務(wù)本身情況,自定義一個(gè)線程池

public static ExecutorService testExtcutor() {
        return new ThreadPoolExecutor(
                2,
                2,
                0L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1));
    }

模擬執(zhí)行

public static void main(String[] args) {
        // 下載文件總數(shù)
        List<Integer> resultList = new ArrayList<>(100);
        IntStream.range(0,100).forEach(resultList::add);
        // 下載文件分段
        List<List<Integer>> split = CollUtil.split(resultList, 10);
        ExecutorService executorService = BaseThreadPoolExector.testExtcutor();
        CountDownLatch countDownLatch = new CountDownLatch(100);
        for (List<Integer> list : split) {
            executorService.execute(() -> {
                list.forEach(i ->{
                    try {
                        // 模擬業(yè)務(wù)操作
                        Thread.sleep(500);
                        System.out.println("任務(wù)進(jìn)入");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        System.out.println(e.getMessage());
                    } finally {
                        System.out.println(countDownLatch.getCount());
                        countDownLatch.countDown();
                    }
                });
            });
        }
        try {
            countDownLatch.await();
            System.out.println("countDownLatch.await()");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

一開始我個(gè)人感覺(jué)沒(méi)有什么問(wèn)題,反正finally都能夠做減一的操作,到最后調(diào)用await方法,進(jìn)行主線程任務(wù)

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@300ffa5d rejected from java.util.concurrent.ThreadPoolExecutor@1f17ae12[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
  at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
  at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
  at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
  at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
  at Thread.executor.executorTestBlock.main(executorTestBlock.java:28)
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown
任務(wù)進(jìn)入
countDownLatch.countDown

由于任務(wù)數(shù)量較多,阻塞隊(duì)列中已經(jīng)塞滿了,所以默認(rèn)的拒絕策略,當(dāng)隊(duì)列滿時(shí),處理策略報(bào)錯(cuò)異常,

要注意這個(gè)異常是線程池,自己拋出的,不是我們循環(huán)里面打印出來(lái)的,

這也造成了,線上這個(gè)線程池被阻塞了,他永遠(yuǎn)也調(diào)用不到await方法,

利用jstack,我們就能夠看到有問(wèn)題

"pool-1-thread-2" #12 prio=5 os_prio=31 tid=0x00007ff6198b7000 nid=0xa903 waiting on condition [0x0000700001c64000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000076b2283f8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
"pool-1-thread-1" #11 prio=5 os_prio=31 tid=0x00007ff6198b6800 nid=0x5903 waiting on condition [0x0000700001b61000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000076b2283f8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

解決方案

調(diào)大阻塞隊(duì)列,但是問(wèn)題來(lái)了,到底多少阻塞隊(duì)列才是大呢,如果太大了會(huì)不由又造成內(nèi)存溢出等其他的問(wèn)題

在第一個(gè)的基礎(chǔ)上,我們修改了拒絕策略,當(dāng)觸發(fā)拒絕策略的時(shí)候,用調(diào)用者所在的線程來(lái)執(zhí)行任務(wù)

 public static ThreadPoolExecutor queueExecutor(BlockingQueue<Runnable> workQueue){
        return new ThreadPoolExecutor(
                size,
                size,
                0L,
                TimeUnit.SECONDS,
                workQueue,
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

你可能又會(huì)想說(shuō),會(huì)不會(huì)任務(wù)數(shù)量太多,導(dǎo)致調(diào)用者所在的線程執(zhí)行不過(guò)來(lái),任務(wù)提交的性能急劇下降

那我們就應(yīng)該自定義拒絕策略,將這下排隊(duì)的消息記錄下來(lái),采用補(bǔ)償機(jī)制的方式去執(zhí)行

同時(shí)也要注意上面的那個(gè)異常是線程池拋出來(lái)的,我們自己也需要將線程池進(jìn)行try catch,記錄問(wèn)題數(shù)據(jù),并且在finally中執(zhí)行countDownLatch.countDown來(lái)避免,線程池的使用

總結(jié)

目前根據(jù)業(yè)務(wù)部門的反饋,業(yè)務(wù)實(shí)際中任務(wù)數(shù)不很特別多的情況,所以暫時(shí)先采用了第二種方式去解決這個(gè)線上問(wèn)題

在這里我們也可以看到,如果沒(méi)有正確的關(guān)閉countDownLatch,可能會(huì)導(dǎo)致一直等待,這也是我們需要注意的。

工具雖然好,但是依然要注意他帶來(lái)的問(wèn)題,沒(méi)有正確的去處理好,引發(fā)的一系列連鎖反應(yīng)。

以上就是java并發(fā)使用CountDownLatch在生產(chǎn)環(huán)境翻車剖析的詳細(xì)內(nèi)容,更多關(guān)于java并發(fā)CountDownLatch的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解Java中數(shù)組判斷元素存在幾種方式比較

    詳解Java中數(shù)組判斷元素存在幾種方式比較

    這篇文章主要介紹了Java中數(shù)組判斷元素存在幾種方式比較,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-07-07
  • Java排序算法之選擇排序代碼實(shí)例

    Java排序算法之選擇排序代碼實(shí)例

    這篇文章主要介紹了Java排序算法之選擇排序代碼實(shí)例,從數(shù)組的第一個(gè)元素開始,每次遍歷數(shù)組找出一個(gè)最小值放在最左側(cè),第二次從第二個(gè)元素開始,依次類推,直到起始元素為數(shù)組的倒數(shù)第二個(gè)元素時(shí),直接和最后一個(gè)元素比較,較小值放左邊,完成排序,需要的朋友可以參考下
    2023-11-11
  • java實(shí)現(xiàn)識(shí)別二維碼圖片功能方法詳解與實(shí)例源碼

    java實(shí)現(xiàn)識(shí)別二維碼圖片功能方法詳解與實(shí)例源碼

    這篇文章主要介紹了java實(shí)現(xiàn)識(shí)別二維碼圖片,java無(wú)法識(shí)別二維碼情況下對(duì)二維碼圖片調(diào)優(yōu)功能方法與實(shí)例源碼,需要的朋友可以參考下
    2022-12-12
  • 聊聊Java BigInteger里面的mod和remainder的區(qū)別

    聊聊Java BigInteger里面的mod和remainder的區(qū)別

    這篇文章主要介紹了聊聊Java BigInteger里面的mod和remainder的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 深入解析Java中的JDBC事務(wù)

    深入解析Java中的JDBC事務(wù)

    這篇文章主要介紹了深入解析Java中的JDBC事務(wù),包含了Java多線程的事務(wù)并發(fā)等知識(shí),需要的朋友可以參考下
    2015-08-08
  • Gateway如何實(shí)現(xiàn)全局跨域

    Gateway如何實(shí)現(xiàn)全局跨域

    這篇文章主要介紹了Gateway如何實(shí)現(xiàn)全局跨域問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 詳解maven依賴沖突以及解決方法

    詳解maven依賴沖突以及解決方法

    這篇文章主要介紹了maven依賴沖突以及解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • java.lang.NoClassDefFoundError錯(cuò)誤解決辦法

    java.lang.NoClassDefFoundError錯(cuò)誤解決辦法

    這篇文章主要介紹了java.lang.NoClassDefFoundError錯(cuò)誤解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java中輸入與輸出的方法總結(jié)

    Java中輸入與輸出的方法總結(jié)

    這篇文章主要為大家總結(jié)了一下Java中輸入與輸出的三種方法,文中通過(guò)示例詳細(xì)的講解了一下這些方法的使用,需要的小伙伴可以參考一下
    2022-04-04
  • Java數(shù)組常用排序算法實(shí)例小結(jié)

    Java數(shù)組常用排序算法實(shí)例小結(jié)

    這篇文章主要介紹了Java數(shù)組常用排序算法,結(jié)合實(shí)例形式總結(jié)分析了java數(shù)組常用的4種排序算法,包括冒泡排序、數(shù)組遞增排序、快速排序及選擇排序,需要的朋友可以參考下
    2017-12-12

最新評(píng)論

土默特左旗| 大渡口区| 柘城县| 河东区| 峨山| 英德市| 黄山市| 西乌珠穆沁旗| 双鸭山市| 黎城县| 北流市| 台南县| 文山县| 鄯善县| 宜丰县| 巴东县| 曲麻莱县| 长岛县| 白银市| 金溪县| 法库县| 岢岚县| 北京市| 金山区| 五寨县| 昌平区| 桃园县| 琼结县| 罗江县| 盐城市| 乐业县| 黄冈市| 孟州市| 阿鲁科尔沁旗| 盘锦市| 右玉县| 临朐县| 卢龙县| 岑溪市| 桓台县| 正宁县|