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

Java 並發編程:線程同步機制深度解析——CountDownLatch、CyclicBarrier、Semaphore、Exchanger

     編輯:Java 綜合教學

Java 並發編程:線程同步機制深度解析——CountDownLatch、CyclicBarrier、Semaphore、Exchanger

第一節 CountDownLatch(倒計時閂)

1. 核心概念

CountDownLatch概念圖1 CountDownLatch概念圖2 CountDownLatch概念圖3

2. 詳細機制

CountDownLatch 通過一個計數器實現,初始值為線程數量。每個線程完成任務後調用 countDown() 使計數器減 1,當計數器歸零時,在 await() 处等待的線程恢復執行。

核心方法:

  • public CountDownLatch(int count):構造函數,count 為需等待的線程數,只能設置一次,無重置機制。
  • public void countDown():計數器減 1,通知機制由此完成。
  • public void await() throws InterruptedException:當前線程阻塞,直到計數器為 0。
CountDownLatch方法詳解1 CountDownLatch方法詳解2 CountDownLatch方法詳解3

3. 代碼示例

package com.test;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String args[]) throws Exception {
        CountDownLatch latch = new CountDownLatch(3);
        Worker worker1 = new Worker("Jack 程序員1", latch);
        Worker worker2 = new Worker("Rose 程序員2", latch);
        Worker worker3 = new Worker("Json 程序員3", latch);
        worker1.start();
        worker2.start();
        worker3.start();
        latch.await(); // 主線程阻塞
        System.out.println("Main thread end!");
    }

    static class Worker extends Thread {
        private String workerName;
        private CountDownLatch latch;
        public Worker(String workerName, CountDownLatch latch) {
            this.workerName = workerName;
            this.latch = latch;
        }
        @Override
        public void run() {
            try {
                System.out.println("Worker:" + workerName + " is begin.");
                Thread.sleep(1000L);
                System.out.println("Worker:" + workerName + " is end.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            latch.countDown(); // 任務完成,計數器-1
        }
    }
}

運行結果:

Worker:Rose 程序員2 is begin.
Worker:Json 程序員3 is begin.
Worker:Jack 程序員1 is begin.
Worker:Jack 程序員1 is end.
Worker:Json 程序員3 is end.
Worker:Rose 程序員2 is end.
Main thread end!

主線程在 latch.await() 處阻塞,直到三個工作線程全部完成。

4. 參考資料


第二節 CyclicBarrier(循環柵欄)

1. 核心概念

CyclicBarrier概念圖1 CyclicBarrier概念圖2 CyclicBarrier概念圖3

2. 應用場景與示例

場景: 大型任務拆分為多個子任務,所有子任務完成後才能執行主任務。

package com.test;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String args[]) throws Exception {
        CyclicBarrier barrier = new CyclicBarrier(3, new TotalTask());
        BillTask worker1 = new BillTask("111", barrier);
        BillTask worker2 = new BillTask("222", barrier);
        BillTask worker3 = new BillTask("333", barrier);
        worker1.start();
        worker2.start();
        worker3.start();
        System.out.println("Main thread end!");
    }

    static class TotalTask extends Thread {
        public void run() {
            System.out.println("所有子任務都執行完了,就開始執行主任務了。");
        }
    }

    static class BillTask extends Thread {
        private String billName;
        private CyclicBarrier barrier;
        public BillTask(String workerName, CyclicBarrier barrier) {
            this.billName = workerName;
            this.barrier = barrier;
        }
        @Override
        public void run() {
            try {
                System.out.println("市區:" + billName + "運算開始:");
                Thread.sleep(1000L);
                System.out.println("市區:" + billName + "運算完成,等待中...");
                barrier.await(); // 等待所有線程到達
                System.out.println("全部都結束,市區" + billName + "才開始後面的工作。");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

運行結果:

市區:111運算開始:
市區:333運算開始:
Main thread end!
市區:222運算開始:
市區:333運算完成,等待中...
市區:222運算完成,等待中...
市區:111運算完成,等待中...
所有子任務都執行完了,就開始執行主任務了。 // 最後到達await的線程執行
全部都結束,市區111才開始後面的工作。
全部都結束,市區222才開始後面的工作。
全部都結束,市區333才開始後面的工作。

關鍵點: 構造 CyclicBarrier 時傳入 Runnable 實現類(TotalTask),所有線程到達 await() 後一起繼續,最後到達的線程執行 TotalTask.run()。若無傳入 Runnable,則直接一起返回繼續執行。

3. CyclicBarrier vs CountDownLatch

特性CountDownLatchCyclicBarrier
作用1或N個線程等待其他線程完成N個線程相互等待
計數器重置不可重置可重置(循環使用)

第三節 Semaphore(信號量)

1. 核心概念

Java Semaphore 用於線程間傳遞信號,維護一組許可。概念上對可用許可計數,常用於資源池(如數據庫連接池)。

Semaphore概念圖1 Semaphore概念圖2 Semaphore概念圖3

2. 代碼示例

場景: 服務器資源有限,同一時刻僅允許 3 人訪問,共 10 人請求。

package com.test;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String args[]) throws Exception {
        final Semaphore semaphore = new Semaphore(3); // 僅允許3個許可
        for (int i = 0; i < 10; i++) {
            final int no = i;
            Runnable thread = new Runnable() {
                public void run() {
                    try {
                        System.out.println("用戶" + no + "連接上了:");
                        Thread.sleep(300L);
                        semaphore.acquire(); // 獲取許可
                        System.out.println("用戶" + no + "開始訪問後台程序...");
                        Thread.sleep(1000L); // 模擬訪問
                        semaphore.release(); // 釋放許可
                        System.out.println("用戶" + no + "訪問結束。");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            new Thread(thread).start();
        }
        System.out.println("Main thread end!");
    }
}

運行結果:

用戶1連接上了:
用戶3連接上了:
用戶4連接上了:
用戶2連接上了:
用戶0連接上了:
用戶5連接上了:
用戶7連接上了:
Main thread end!
用戶6連接上了:
用戶8連接上了:
用戶9連接上了:
用戶3開始訪問後台程序...
用戶4開始訪問後台程序...
用戶2開始訪問後台程序...
用戶4訪問結束。
用戶3訪問結束。
用戶7開始訪問後台程序...
用戶0開始訪問後台程序...
用戶8開始訪問後台程序...
用戶2訪問結束。
用戶5開始訪問後台程序...
用戶0訪問結束。
用戶7訪問結束。
用戶1開始訪問後台程序...
用戶8訪問結束。
用戶6開始訪問後台程序...
用戶1訪問結束。
用戶9開始訪問後台程序...
用戶5訪問結束。
用戶6訪問結束。
用戶9訪問結束。

10 個線程同時啟動,但始終只有 3 個線程能同時獲得許可訪問資源,釋放一個進來一個。

3. 參考資料

https://ifeve.com/semaphore/


第四節 Exchanger(交換器)

1. 核心概念

與前三種基於計數器的同步機制不同,Exchanger 用於成對出現的線程之間交換數據(兩個線程共享一個 Exchanger)。

Exchanger概念圖1 Exchanger概念圖2

2. 代碼示例

Exchanger示例1 Exchanger示例2 Exchanger示例3

3. 參考資料

https://www.cnblogs.com/davidwang456/p/4179488.html

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved