Java項目實踐,CountDownLatch實現多線程閉鎖

2021-01-09 Java技術匯

摘要

本文主要介紹Java多線程並發中閉鎖(Latch)的基本概念、原理、示例代碼、應用場景,通過學習,可以掌握多線程並發時閉鎖(Latch)的使用方法。

概念

「閉鎖」就是指一個被鎖住了的門將線程a擋在了門外(等待執行),只有當門打開後(其他線程執行完畢),門上的鎖才會被打開,a才能夠繼續執行。

閉鎖(Latch),目的是使多個線程在完成各自任務後,才會打開繼續執行後面的任務,否則一直等待。

計數器閉鎖(CountDownLatch)是一個同步工具類, 可以用來協調多個線程的執行時間,允許一個或多個線程等待某個事件的發生。

CountDownLatch有個正數的計數器,countDown(); 對計數器做減法操作,await(); 等待計數器等於0。所有await的線程都會阻塞,直到計數器為0或者等待線程中斷或者超時。

例如, 可以讓a線程在其他線程運行完畢後再執行。如果其他線程沒有執行完畢,則a線程就會一直等待。

原理分析

CountDownLatch的實現原理:

1、CountDownLatch在創建時, 會指定一個計數器,表示等待線程的執行數量(比如,3就表示當3個線程執行完畢後,再結束閉鎖,使a能夠繼續執行);

2、 其他每個線程在各自執行完畢時, 分別調用一次countDown())方法,用來遞減計數器, 表示有一個線程已經執行完畢了;這時, 線程a可以調用await()方法, 用來等待計數器的值為0。

3、如果計數器的值大於0, 那麼await()方法會一直阻塞, 直到計數器為0時,線程a才會繼續執行;

4、如果線程a一直無法等到計數器為0,則會顯示等待超時,當然也可以在線程a等待時,通過程序中斷等待。

示例代碼

在Java中, 可以使用CountDownLatch實現多線程閉鎖,具體實現代碼如下:

public class JavaLearnsCountDownLatch {

public static void main(String[] args) {

//計數器為8

CountDownLatch countDownLatch = new CountDownLatch(8);

//將CountDownLatch對象傳遞到線程的run()方法中,當每個線程執行完畢run()後就將計數器減1

MyThread myThread = new MyThread(countDownLatch);

long start = System.currentTimeMillis();

//創建8個線程,並執行

for (int i = 0; i <8; i++) {

new Thread(myThread).start();

}

try {

//主線程(main)等待:等待的計數器為0;即當CountDownLatch中的計數器為0時,Main線程才會繼續執行。

countDownLatch.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

long end = System.currentTimeMillis();

System.out.println("耗時:" + (end - start));

}

}

class MyThread implements Runnable {

private CountDownLatch latch;

public MyThread(CountDownLatch latch) {

this.latch = latch;

}

@Override

public void run() {

try {

Thread.sleep(5000);

}catch (InterruptedException e){

e.printStackTrace();

}

finally {

latch.countDown();//每個子線程執行完畢後,觸發一次countDown(),即計數器減1

}

}

}

應用場景

1、確保某個計算,在其需要的所有資源都準備就緒後再執行,比如:要計算某個工程材料的合價,要知道材料的單價和工程量後,才能執行材料合價計算。

2、確保某個服務,在其依賴的所有其他服務都已經啟動後再啟動。

3、確保某個任務,在所有參與者都準備就緒後再執行,比如:線上上課,在全班30個同學都全部上線後,老師才能開始上課。

我是一名碼齡10年的程式設計師,在這裡會分享實在乾貨,讓你少走彎路,成就精彩人生。

相關焦點

  • 項目實踐,使用Cyclic Barrier在多線程中設置屏障
    柵欄類似於閉鎖,它能阻塞一組線程直到某個事件的發生。柵欄與閉鎖的關鍵區別在於,所有的線程必須同時到達柵欄位置,才能繼續執行。閉鎖用於等待事件,而柵欄用於等待其他線程。Cyclic Barrer也可以用於解決多個線程之間的相互等待問題。
  • 淺談Java中的幾種隨機數
    猜你可能想到了java.lang.Math,很好,我們就是改良java.lang.Math的初始化。雖然這個工程量低,但你也要做一些簡單的單元測試來確保其不會出錯。假設程序需要生成一個隨機數來存儲,問題就又來了。比如有時需要操作或保護種子(seed),一個內部數用來存儲狀態和計算下一個隨機數。在這些特殊情況下,共用隨機生成對象是不合適的。
  • Java程式設計師必備基礎:Java代碼是怎麼運行的?
    運行時創建對象 方法調用,執行引擎解釋為機器碼 CPU執行指令 多線程切換上下文 編譯 我們都知道,java代碼是運行在Java虛擬機上的。
  • 優雅終止線程?系統內存佔用較高?
    摘要:該項目是DAYU平臺的數據開發(DLF),數據開發中一個重要的功能就是ETL(數據清洗)。ETL由源端到目的端,中間的業務邏輯一般由用戶自己編寫的SQL模板實現,velocity是其中涉及的一種模板語言。
  • JAVA專業術語面試100問
    StringBuilder:適用於單線程下在字符緩衝區進行大量操作的情況(是線程不安全的)StringBuffer:適用多線程下在字符緩衝區進行大量操作的情況(一般很少)(是線程安全的)首先說運行速度,或者說是執行速度,在這方面運行速度快慢為:StringBuilder >
  • Java NIO 基礎知識
    那就意味著,一旦請求數量多了以後,需要創建大量的線程,大量的線程必然帶來創建線程、切換線程的開銷,更重要的是,要給每個線程都分配一部分內存,會使得內存迅速被消耗殆盡。我們說多線程是性能利器,但是這就是過多的線程導致系統完全消化不了了。通常,我們可以將 IO 分為兩類:面向數據塊(block-oriented)的 IO 和面向流(stream-oriented)的 IO。
  • 「軟帝學院」Java挑戰者專欄:多線程詳解2
    多線程的問題?>多線程(線程的五種狀態)(掌握)看圖說話新建,就緒,運行,阻塞,死亡多線程(線程池的概述和使用)(了解)A:線程池概述pool.submit(new MyRunnable());pool.submit(new MyRunnable());//結束線程池pool.shutdown();多線程(多線程程序實現的方式3)(了解)提交的是Callable
  • Java常見內存溢出異常分析
    如果應用程式本身比較大,涉及的類庫比較多,但是我們分配給持久帶的內存(通過-XX:PermSize和-XX:MaxPermSize來設置)比較小的時候也可能出現此種問題。   一些第三方框架,比如spring,hibernate都通過字節碼生成技術(比如CGLib)來實現一些增強的功能,這種情況可能需要更大的方法區來存儲動態生成的Class文件。
  • Java 生成隨機數的 5 種方式,你知道幾種?
    方法是 的,因此在多線程情況下,只有一個線程會負責創建偽隨機數生成器(使用當前時間作為種子),其他線程則利用該偽隨機數生成器產生隨機數。Java生成隨機數的幾種高級用法,這篇推薦看一下。 因此 方法是線程安全的。
  • aio-enhance v1.0.2 發布,Java AIO 內核增強類庫
    aio-enhance 採用了 NIO 技術實現了一套全新的異步 IO 模型,兼容完整的 Java AIO 接口。用戶可自由選擇 Java 原生提供的,或者 aio-enhance 增強的 AIO 實現,架構如下圖。
  • Java研發技術——Volatile原理詳解
    所以,在多處理器下,為了保證各個處理器的緩存是一致的,就會實現緩存一致性協議,每個處理器通過嗅探在總線上傳播的數據來檢查自己緩存的值是不是過期了,當處理器發現自己緩存行對應的內存地址被修改,就會將當前處理器的緩存行設置成無效狀態,當處理器對這個數據進行修改操作的時候,會重新從系統內存中把數據讀到處理器緩存裡。
  • 開發崗位這麼多,為什麼選Java?你學Java了嗎-開課吧
    軟體開發可以使用的語法是非常多,但是為什麼Java被廣泛的使用呢?其他程式語言與Java相比,Java語法相對簡單,並且是很多計算機語言的基礎。提到C++語言,很多人發現在使用過程中最容易出現的錯誤就是內存管理,而java有自動垃圾回收器,不用擔心內存。
  • JAVA校招題基礎知識點複習第六天(一張圖搞懂所有集合特點)
    在開發中一般當對象多的時候,使用集合進行存儲。了解完集合與數組的區別,讓我們來看看在JAVA中都為我們提供了哪些集合?在JAVA中,集合按照其存儲結構可以分為兩大類,分別是單列集合java.util.Collection和雙列集合java.util.Map。
  • 2018年阿里巴巴關於Java重要開源項目匯總
    企業級流式計算引擎 JStormJStorm 是參考 Apache Storm 實現的實時流式計算框架,在網絡IO、線程模型、資源調度、可用性及穩定性上做了持續改進,已被越來越多企業使用。JStorm 可以看作是 storm 的 java 增強版本,除了內核用純java實現外,還包括了thrift、python、facet ui。
  • 萬字概覽 Java 虛擬機
    PC Register在多核處理器上,一個時刻只能有一個核進行工作,而多線程情況下,線程可能分布在不同的核心上。當 A 線程任務還沒有處理完時,所在核心失去了 CPU 執行權,此時就需要使用程序計數器記錄當前程序執行的位置,等下次獲得執行權後繼續執行。這個區域是 JVM 規範中唯一一個不會出現 OOM 的區域。
  • 10個相見恨晚的 Java 在線練手項目
    因為百家對外鏈不支持等其他原因,所有項目地址可在實驗樓公號(實驗樓)後臺回復關鍵字 「Java路徑」 獲取。有人認為幸福是財富,是掌聲跟紅地毯,是在冰島的初冬吻一個女孩,是娶妻生子;也許真是這樣,柳惜春,但你知道我怎麼想的麼?我覺的,幸福就是一點一點地變好。Java,新年快樂。
  • 支付寶高級Java現場面試37題:頁鎖+死鎖+集群+雪崩+負載等
    2020-09-26 15:45:21 來源: java架構codi 舉報
  • 萬字梳理,帶你拿下 Java 面試題!
    通過 JIT 即時編譯器來實現高性能。解釋性,Java 被編譯成字節碼,由 Java 運行時環境解釋。多線程性,Java支持多個執行線程(也稱為輕量級進程),包括一組同步原語。這使得使用線程編程更加容易,Java 通過管程模型來實現線程安全性。3、描述一下值傳遞和引用傳遞的區別?
  • linux多線程之線程資源的釋放
    一般來說,對一段運行代碼進行加鎖然後解鎖,如下所示:pthread_mutex_lock(&mutex);//運行代碼;pthread_mutex_unlock(&mutex);如果在運行代碼這塊發生錯誤,有異常,導致這個線程異常退出,那麼怎麼辦,pthread_unlock
  • 程式設計師:java單例模式,為什麼要加雙重鎖?為什麼要加volatile?
    如果說我們沒有第一次驗校,每一個線程都要走synchronized 中的代碼,而每一次線程都要去拿到同步鎖才能執行。在多線程的情況下每一個線程要拿到single 對象都要排隊等待同步鎖釋放。因此第一次驗校作用就是為了提高程序的效率。2.為什麼要進行第二次判空舉個例子:假如現在沒有第二次驗校,線程A執行到第一次驗校那裡,它判斷到single ==null。