Java中的Semaphore和CountDownLatch這兩個工具類的使用方法和實際應用場景

在現代的多線程編程中,Semaphore和CountDownLatch是兩個非常常見和重要的工具類,它們都可以用來實現多線程間的同步和互斥,提高程序的併發性能和效率。本文將詳細介紹Java中的Semaphore和CountDownLatch這兩個工具類的使用方法和實際應用場景。

一、Semaphore

1.1 概述

Semaphore是Java中的一個同步工具類,用來控制多個線程對共享資源的訪問。它主要用於控制併發線程的數量,可以設置一定數量的許可證,每當一個線程訪問共享資源時,會消耗一個許可證,當許可證用盡時,其他線程就會被阻塞,直到有線程釋放許可證爲止。

1.2 使用

Semaphore的常用方法如下:

  • acquire(int permits): 獲取指定數量的許可證,如果沒有足夠的許可證,當前線程將會被阻塞。
  • tryAcquire(int permits): 嘗試獲取指定數量的許可證,如果可以獲取則返回true,否則返回false。
  • release(int permits): 釋放指定數量的許可證,喚醒被阻塞的線程。

使用Semaphore的典型場景是控制線程的併發數量,下面我們來看一個簡單的例子:

import java.util.concurrent.Semaphore;

public class SemaphoreTest {
    public static void main(String[] args) {
        int N = 8; // 任務數
        Semaphore semaphore = new Semaphore(5); // 最大併發數爲5

        for (int i = 0; i < N; i++) {
            new Worker(i, semaphore).start(); // 啓動多個線程
        }
    }

    static class Worker extends Thread {
        private int num;
        private Semaphore semaphore;

        public Worker(int num, Semaphore semaphore) {
            this.num = num;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire(); // 獲取許可證
                System.out.println("Worker " + num + " is working");
                Thread.sleep(2000);
                System.out.println("Worker " + num + " has finished");
                semaphore.release(); // 釋放許可證
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

上面的代碼中,我們創建了一個Semaphore對象,並設置最大併發數爲5。然後創建了8個線程,每當一個線程開始工作時,需要先獲取一個許可證,如果沒有足夠的許可證,則會被阻塞,直到其他線程釋放許可證爲止。這樣就可以有效控制線程的併發數量,避免系統資源過度消耗。

二、CountDownLatch

2.1 概述

CountDownLatch也是Java中的一個同步工具類,它用於控制一個或多個線程等待其他線程完成任務後再執行。CountDownLatch的工作方式比較簡單,它會在初始化時設置一個計數器,每當一個任務完成時,就將計數器減一;當計數器爲0時,代表所有任務都已經完成,等待的線程可以開始執行了。

2.2 使用

CountDownLatch的常用方法如下:

  • CountDownLatch(int count):初始化一個CountDownLatch對象,並設置計數器初始值。
  • void await():調用此方法會使當前線程等待,直到計數器爲0才繼續執行。
  • void countDown():將計數器減1,當計數器爲0時,等待的線程會被喚醒。

下面我們來看一個實際應用場景,假設要求在多個線程中進行文件拆分和合並操作,需要先將文件拆分成若干個塊,然後多個線程並行處理這些塊,最後再將處理結果合併成一個完整的文件。這個需求可以使用CountDownLatch來實現。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {
    private static final int THREAD_COUNT = 4; // 線程數
    private static final CountDownLatch startLatch = new CountDownLatch(1); // 開始信號
    private static final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); // 結束信號

    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " is ready");
                    startLatch.await(); // 等待開始信號
                    System.out.println(Thread.currentThread().getName() + " is working");
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() + " has finished");
                    endLatch.countDown(); // 發送結束信號
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }

        System.out.println("All threads are ready, start working...");
        startLatch.countDown(); // 發送開始信號
        try {
            endLatch.await(); // 等待所有線程結束
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("All threads have finished their work");
    }
}

上面的代碼中,我們創建了4個線程,並使用CountDownLatch來控制線程的同步和互斥。首先創建了兩個CountDownLatch對象,一個用於發出開始信號,一個用於接收結束信號。然後啓動了4個線程,每當一個線程開始工作時,需要等待開始信號發出,如果沒有收到開始信號,則會一直等待;當所有線程都已經完成任務後,需要發送結束信號,以便主線程可以繼續執行。

三、總結

通過以上示例,我們可以看到在實際應用中,Semaphore和CountDownLatch也都是非常實用的工具類,它們可以幫助程序員有效控制多線程的併發數量和任務執行順序,提高程序的性能和效率。有了這兩個工具類的幫助,我們可以更加方便地進行多線程編程,實現更加複雜的業務邏輯。需要注意的是,在使用這兩個工具類時,應該結合實際需求場景來選擇合適的方法和參數,避免程序出現不必要的死鎖和阻塞。

 

Java線程池ThreadPoolExecutor詳解和CountDownLatch的使用(非常詳細)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章