Cách sử dụng Java CountDownLatch

2 min read

Giới thiệu

Trong bài viết này, chúng ta sẽ xem cách sử dụng Java CountDownLatch để viết các trường hợp kiểm thử có tính đến tính đồng thời.

Java CountDownLatch đã có sẵn từ phiên bản 1.5 và là một phần của gói java.util.concurrent chứa nhiều tiện ích liên quan đến luồng khác.

Lớp Java CountDownLatch

Lớp Java CountDownLatch cung cấp các phương thức sau:

Các phương thức quan trọng nhất là await và countDown.

Phương thức await được sử dụng để tạm dừng việc thực thi luồng hiện tại cho đến khi bộ đếm của CountDownLatch đạt giá trị 0 hoặc luồng bị gián đoạn.

Phương thức countDown được sử dụng để giảm giá trị của bộ đếm nội bộ.

Do đó, mục tiêu của lớp Java CountDownLatch là kiểm soát thời điểm khi một hoặc nhiều luồng đang chờ trên CountDownLatch sẽ tiếp tục thực thi.

Kết hợp với Java Thread

Giả sử chúng ta có ví dụ sau trong đó chúng ta bắt đầu 5 worker thread từ main thread:

@Test
public void testNoCoordination() {
    LOGGER.info("Main thread starts");
⠀
    int workerThreadCount = 5;
⠀
    for (int i = 1; i <= workerThreadCount; i++) {
        String threadId = String.valueOf(i);
        new Thread(
            () -> LOGGER.info(
                "Worker thread {} runs",
                threadId
            ),
            "Thread-" + threadId
        ).start();
    }
⠀
    LOGGER.info("Main thread finishes");
}

Khi chạy test case trên, chúng ta nhận được kết quả như sau:

[main]: Main thread starts
[main]: Main thread finishes
[Thread-4]: Worker thread 4 runs
[Thread-1]: Worker thread 1 runs
[Thread-5]: Worker thread 5 runs
[Thread-3]: Worker thread 3 runs
[Thread-2]: Worker thread 2 runs

Main thread bắt đầu và kết thúc trước khi các worker thread được thực thi và đây có thể là một vấn đề nếu chúng ta muốn chạy một số xác nhận để xác thực kết quả của việc thực thi worker thread.

Vì vậy, chúng ta cần phối hợp main thread và các worker thread sao cho main thread đợi các worker thread kết thúc trước khi thực hiện xong chính nó.

Với mục đích này, chúng tôi sẽ sử dụng CountDownLatch để điều phối các main thread và worker thread:

@Test
public void testCountDownLatch() throws InterruptedException {
    LOGGER.info("Main thread starts");
⠀
    int workerThreadCount = 5;
⠀
    CountDownLatch endLatch = new CountDownLatch(workerThreadCount);
⠀
    for (int i = 1; i <= workerThreadCount; i++) {
        String threadId = String.valueOf(i);
        new Thread(
            () -> {
                LOGGER.info(
                    "Worker thread {} runs",
                    threadId
                );
⠀
                endLatch.countDown();
            },
            "Thread-" + threadId
        ).start();
    }
⠀
    LOGGER.info("Main thread waits for the worker threads to finish");
⠀
    endLatch.await();
⠀
    LOGGER.info("Main thread finishes");
}

Được endLatch tạo với giá trị bộ đếm khớp với số lượng worker thread

Main thread sẽ chờ trên endLatch, và việc thực thi nó sẽ chỉ được tiếp tục khi giá trị bộ đếm dạy giá trị của 0.

Bởi vì mỗi worker thread giảm giá trị bộ đếm bằng cách sử dụng lệnh countDown gọi phương thức, nên sau khi tất cả các worker thread kết thúc, bộ đếm sẽ đạt giá trị 0 và main thread sẽ tiếp tục thực thi.

Khi thực hiện testCountDownLatch test case, chúng ta có thể thấy CountDownLatch hoạt động như mong đợi:

[main]: Main thread starts
[main]: Main thread waits for the worker threads to finish
[Thread-1]: Worker thread 1 runs
[Thread-3]: Worker thread 3 runs
[Thread-2]: Worker thread 2 runs
[Thread-5]: Worker thread 5 runs
[Thread-4]: Worker thread 4 runs
[main]: Main thread finishes

Lần này, main thread đợi các worker thread kết thúc trước khi kết thúc quá trình thực thi của chính nó.

Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *