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

java線程并發(fā)控制同步工具CountDownLatch

 更新時間:2022年08月10日 10:15:36   作者:叫我小郭  
這篇文章主要為大家介紹了java線程并發(fā)控制同步工具CountDownLatch使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

大家好,我是小郭,前面我們學(xué)習(xí)了利用Semaphore來防止多線程同時操作一個資源,通常我們都會利用并行來優(yōu)化性能,但是對于串行化的業(yè)務(wù),可能需要按順序執(zhí)行,那我們怎么才能處理呢?今天我們來學(xué)習(xí)另一個并發(fā)流程控制的同步工具CountDownLatch。

了解CountDownLatch

首先,CountDownLatch是一種并發(fā)流程控制的同步工具。

主要的作用是等待多個線程同時完成任務(wù)之后,再繼續(xù)完成主線程任務(wù)。

簡單點可以理解為,幾個小伙伴一起到火鍋店聚餐,人到齊了,火鍋店才可以開飯。

思考問題:

  • CountDownLatch 底層原理是什么,他是否可以代替wait / notify?
  • CountDwonLatch 業(yè)務(wù)場景有哪些?
  • 一次可以喚醒多個任務(wù)嗎?

主要參數(shù)與方法

//減少鎖存器的計數(shù),如果計數(shù)達到零,則釋放所有等待線程。 
//計數(shù)器 
public void countDown() { 
    sync.releaseShared(1); 
} 
//導(dǎo)致當前線程等待,直到鎖存器遞減至零為止,除非該線程被中斷。 
//火鍋店調(diào)用await的線程,count為0才能繼續(xù)執(zhí)行 
public void await() throws InterruptedException { 
    sync.acquireSharedInterruptibly(1); 
}

構(gòu)造方法

//count 數(shù)量,理解為小伙伴的個數(shù) 
public CountDownLatch(int count) { 
    if (count < 0) throw new IllegalArgumentException("count < 0"); 
        this.sync = new Sync(count); 
} 
//獲取剩余的數(shù)量 
public long getCount() { 
    return sync.getCount(); 
}

CountDownLatch底層實現(xiàn)原理

我們可以看出countDown()是CountDownLatch的核心方法,我來看下他的具體實現(xiàn)。

CountDownLatch來時繼承AQS的共享模式來完成其的實現(xiàn),從前面的學(xué)習(xí)得出AQS主要是依賴同步隊列和state實現(xiàn)控制。

共享模式:

這里與獨占鎖大多數(shù)相同,自旋過程中的退出條件是是當前節(jié)點的前驅(qū)節(jié)點是頭結(jié)點并且tryAcquireShared(arg)返回值大于等于0即能成功獲得同步狀態(tài).

await

public boolean await(long timeout, TimeUnit unit) throws InterruptedException { 
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); 
} 
//當狀態(tài)不為0掛起,表示當前線程被占有,需要線程排隊 
protected int tryAcquireShared(int acquires) { 
    return (getState() == 0) ? 1 : -1; 
} 
//在共享模式下獲取 
doAcquireSharedInterruptibly(int arg)

countDown

public void countDown() { 
    sync.releaseShared(1); 
} 
protected boolean tryReleaseShared(int releases) { 
// Decrement count; signal when transition to zero 
//自旋防止失敗 
    for (;;) { 
        //獲取狀態(tài)
        int c = getState(); 
        //狀態(tài)為為0返回false,表示沒有被線程占有 
        if (c == 0) return false; 
        //調(diào)用cas來進行替換,也保證了線程安全,當為0的時候喚醒 
        int nextc = c-1; 
        if (compareAndSetState(c, nextc)) 
            return nextc == 0; 
    } 
} 
//當任務(wù)數(shù)量為0,aqs的釋放共享鎖 
void doReleaseShared()
private void doReleaseShared() {
    /*
        * Ensure that a release propagates, even if there are other
        * in-progress acquires/releases.  This proceeds in the usual
        * way of trying to unparkSuccessor of head if it needs
        * signal. But if it does not, status is set to PROPAGATE to
        * ensure that upon release, propagation continues.
        * Additionally, we must loop in case a new node is added
        * while we are doing this. Also, unlike other uses of
        * unparkSuccessor, we need to know if CAS to reset status
        * fails, if so rechecking.
        */
    // 無限循環(huán)
    for (;;) {
        // 保存頭節(jié)點
        Node h = head;
        // 頭節(jié)點不為空并且頭節(jié)點不為尾結(jié)點
        if (h != null && h != tail) { 
            // 獲取頭節(jié)點的等待狀態(tài)
            int ws = h.waitStatus; 
            if (ws == Node.SIGNAL) { 
                // 狀態(tài)為SIGNAL,CAS更新狀態(tài)
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) 
                    continue;            // loop to recheck cases
                // 釋放后繼結(jié)點
                unparkSuccessor(h);
            }
            // 狀態(tài)為0并且更新不成功,繼續(xù)
            else if (ws == 0 &&
                        !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) // 
                continue;                // loop on failed CAS
        }
        if (h == head) // 若頭節(jié)點改變,繼續(xù)循環(huán)  
            break;
    }
}

思考

  • 如何安排線程排序

個人認為,沒有進行線程的排序,而是讓一部分線程進入等待,在喚醒的時候放開。

執(zhí)行流程圖

實踐

用法一:

一個線程等待其他多個線程都執(zhí)行完畢,再繼續(xù)自己的工作

public class CountDownLatchTest {
    private static Lock lock = new ReentrantLock();
    private static CountDownLatch countDownLatch = new CountDownLatch(4);
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        IntStream.range(0,16).forEach(i -&gt;{
            executorService.submit(()-&gt;{
                lock.lock();
                System.out.println(Thread.currentThread().getName()+ "來火鍋店吃火鍋!");
                try {
                    Thread.sleep(1000);
                    countDownLatch.countDown();
                    System.out.println(Thread.currentThread().getName() + "我到火鍋店了,準備開吃!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            });
        });
        try {
            countDownLatch.await(5,TimeUnit.SECONDS);
            System.out.println("人到齊了,開飯");
            executorService.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

輸出結(jié)果

代碼中設(shè)置了一個CountDownLatch做倒計時,四個人(count為4)一起到火鍋店吃飯,每到一個人計數(shù)器就減去1(countDownLatch.countDown()),當計數(shù)器為0的時候,main線程在await的阻塞結(jié)束,繼續(xù)往下執(zhí)行。

用法二:

多個線程等待某一個線程的信號,同時開始執(zhí)行

用搶位子作為例子,將線程掛起等待,同時開始執(zhí)行。

public class CountDownLatchTest2 {
    private static Lock lock = new ReentrantLock();
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        IntStream.range(0,4).forEach(i ->{
            executorService.submit(()->{
                System.out.println(Thread.currentThread().getName()+ "準備開始搶位子!");
                try {
                    //Thread.sleep(1000);
                    countDownLatch.await();
                    System.out.println(Thread.currentThread().getName() + "搶到了位置");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        });
        try {
            Thread.sleep(5000);
            System.out.println("五秒后開始搶位置");
            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }
}

注意點

CountDownLatch是不能重用的。

總結(jié)

我們可以看到CountDownLatch的使用很簡單,就當做一個計時器來使用,在控制并發(fā)方面能給我們提供幫助。

  • 在構(gòu)造器中初始化任務(wù)數(shù)量
  • 調(diào)用await()掛起主線程main
  • 調(diào)用countDown()方法減一,直到為0的時候,喚醒主線程可以繼續(xù)運行。

上面提供的兩個用法,我們也可以結(jié)合起來使用。

在實際的業(yè)務(wù)代碼開發(fā)中,利用CountDownLatch來進行業(yè)務(wù)方法的執(zhí)行,來確定他們的順序,解決一個線程等待多個線程的場景

以上就是java線程并發(fā)控制同步工具CountDownLatch的詳細內(nèi)容,更多關(guān)于java線程并發(fā)CountDownLatch的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Java反射獲取方法的全路徑名稱的步驟

    使用Java反射獲取方法的全路徑名稱的步驟

    Java反射是一個強大的特性,它允許程序在運行時查詢和修改類的行為,反射可以用于實現(xiàn)很多高級功能,比如動態(tài)代理、依賴注入等,本文將介紹如何使用Java反射來實現(xiàn)這一功能,需要的朋友可以參考下
    2024-07-07
  • 從實戰(zhàn)角度詳解Disruptor高性能隊列

    從實戰(zhàn)角度詳解Disruptor高性能隊列

    這篇文章主要介紹了從實戰(zhàn)角度詳解Disruptor高性能隊列,對正在學(xué)習(xí)這方面知識的小伙伴有很大的幫助,感興趣的小伙伴快來一起學(xué)習(xí)吧
    2021-08-08
  • 使用SpringBoot整合ssm項目的實例詳解

    使用SpringBoot整合ssm項目的實例詳解

    Spring Boot 現(xiàn)在已經(jīng)成為 Java 開發(fā)領(lǐng)域的一顆璀璨明珠,它本身是包容萬象的,可以跟各種技術(shù)集成。這篇文章主要介紹了使用SpringBoot整合ssm項目,需要的朋友可以參考下
    2018-11-11
  • SpringBoot集成ECDH密鑰交換的方法

    SpringBoot集成ECDH密鑰交換的方法

    ECDH密鑰交換算法通過橢圓曲線和Diffie-Hellman方法生成共享密鑰,用于前端和后端之間的AES加密通信,前端使用elliptic.js生成密鑰對,后端使用crypto-js.min.js進行AES加密,本文給大家介紹SpringBoot集成ECDH密鑰交換的相關(guān)知識,感興趣的朋友一起看看吧
    2025-01-01
  • Arthas-java程序運行時debug工具使用

    Arthas-java程序運行時debug工具使用

    這篇文章主要介紹了Arthas-java程序運行時debug工具使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java利用Request請求獲取IP地址的方法詳解

    Java利用Request請求獲取IP地址的方法詳解

    在開發(fā)中我們經(jīng)常需要獲取用戶IP地址,通過地址來實現(xiàn)一些功能,下面這篇文章主要給大家介紹了關(guān)于Java利用Request請求獲取IP地址的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • 使用阿里云OSS的服務(wù)端簽名后直傳功能的流程分析

    使用阿里云OSS的服務(wù)端簽名后直傳功能的流程分析

    這篇文章主要介紹了使用阿里云OSS的服務(wù)端簽名后直傳功能,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • java中實現(xiàn)遞歸計算二進制表示中1的個數(shù)

    java中實現(xiàn)遞歸計算二進制表示中1的個數(shù)

    這是一個很有意思的問題,是在面試中特別容易被問到的問題之一,解決這個問題第一想法肯定是一位一位的去判斷,是1計數(shù)器+1,否則不操作,跳到下一位,十分容易,編程初學(xué)者就可以做得到!
    2015-05-05
  • Java 在PPT中創(chuàng)建散點圖的實現(xiàn)示例

    Java 在PPT中創(chuàng)建散點圖的實現(xiàn)示例

    本文將以Java代碼示例展示如何在PPT幻燈片中創(chuàng)建散點圖表。文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Mybatis中的Criteria條件查詢方式

    Mybatis中的Criteria條件查詢方式

    這篇文章主要介紹了Mybatis中的Criteria條件查詢方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論

永清县| 四川省| 农安县| 徐汇区| 东平县| 潞城市| 连江县| 白城市| 尚义县| 汕尾市| 仪陇县| 什邡市| 温宿县| 延津县| 枣强县| 临江市| 胶南市| 呈贡县| 玉门市| 卓尼县| 宜宾县| 彭州市| 兴安县| 榕江县| 嘉义县| 佛坪县| 黄龙县| 贵溪市| 长丰县| 丹巴县| 宜宾市| 舞阳县| 高青县| 海兴县| 普兰县| 凭祥市| 德阳市| 新昌县| 长兴县| 合阳县| 玉山县|