首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 並發編程:CountDownLatch 閉鎖機制實戰詳解

     編輯:Java 相關知識

CountDownLatch 核心概念

CountDownLatch(倒數閂鎖)是一種同步輔助類,允許一個或多個線程等待其他線程完成操作。它就像一扇門:在計數器歸零前門保持關閉,所有等待線程阻塞;計數器歸零時門打開,所有等待線程同時被釋放繼續執行。

核心 API

  • CountDownLatch(int count):建構子,初始化計數器
  • void countDown():計數器減 1,表示一個任務完成
  • void await():阻塞當前線程,直到計數器歸零
  • boolean await(long timeout, TimeUnit unit):帶超時的等待
  • long getCount():獲取當前計數值

經典應用場景:賽跑模擬

10 位運動員等待裁判發令同時起跑,當最後一名到達終點時比賽結束。這需要兩個閉鎖協調:

  1. 起跑閉鎖:計數 1,所有運動員 await() 等待裁判 countDown()
  2. 結束閉鎖:計數 10,每位運動員到達終點 countDown(),裁判 await() 等待所有人完成

完整代碼實作

import java.util.concurrent.CountDownLatch;

class Runner implements Runnable {
    private final int id;
    private final CountDownLatch startSignal;
    private final CountDownLatch finishSignal;

    public Runner(int id, CountDownLatch startSignal, CountDownLatch finishSignal) {
        this.id = id;
        this.startSignal = startSignal;
        this.finishSignal = finishSignal;
    }

    @Override
    public void run() {
        try {
            System.out.println(id + " 號選手準備就緒");
            startSignal.await(); // 等待發令
            
            // 模擬跑步時間
            Thread.sleep((long) (Math.random() * 3000));
            
            System.out.println(id + " 號選手到達終點");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            finishSignal.countDown(); // 到達終點,計數器減一
        }
    }
}

public class RaceSimulation {
    public static void main(String[] args) throws InterruptedException {
        int runnerCount = 10;
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch finishSignal = new CountDownLatch(runnerCount);

        // 啟動所有選手線程
        for (int i = 1; i <= runnerCount; i++) {
            new Thread(new Runner(i, startSignal, finishSignal)).start();
        }

        System.out.println("裁判準備發令...");
        Thread.sleep(1000);
        System.out.println("裁判:開始跑!");
        startSignal.countDown(); // 發令

        long startTime = System.nanoTime();
        finishSignal.await(); // 等待所有選手到達
        long endTime = System.nanoTime();

        System.out.println("裁判:所有人到達終點!");
        System.out.printf("比賽耗時:%.2f 秒%n", (endTime - startTime) / 1e9);
    }
}

關鍵區別:CountDownLatch vs CyclicBarrier

特性CountDownLatchCyclicBarrier
可重用性一次性,計數歸零不可重置可重用,攔截點可重置
等待對象等待事件(countDown)等待其他線程(await)
適用場景一線程等多線程完成多線程互相等待匯合
攔截動作不支援支援 barrierAction

常見陷阱與注意事項

  • 計數器不可重置:一次性使用,需重新 new 實例
  • countDown 不拋異常:計數器已為 0 時再調用不會拋異常,只會無視
  • await 可被中斷:需處理 InterruptedException,建議恢復中斷狀態
  • 不保證公平性:釋放順序不確定
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved