0
0
Lập trình
Thaycacac
Thaycacac thaycacac

Giới thiệu về CountDownLatch và CyclicBarrier trong Lập trình Đa luồng Java

Đăng vào 2 tuần trước

• 6 phút đọc

Chủ đề:

android và java

Trong lập trình đa luồng (multi-threading) với Java, việc đồng bộ hóa các luồng để đảm bảo rằng các tác vụ được thực hiện theo trình tự nhất định là rất cần thiết. Hai lớp hữu ích hỗ trợ cho việc này trong Java là CountDownLatchCyclicBarrier. Dưới đây là phân tích chi tiết về cách thức hoạt động và ứng dụng của từng lớp.

1. CountDownLatch

Nguyên lý hoạt động

Lớp CountDownLatch cho phép chúng ta khởi động một thread X ngay sau khi tất cả các thread A1, A2, A3,... đã hoàn thành. CountDownLatch sử dụng một biến đếm nội bộ, khác với Semaphore, rằng biến đếm này chỉ được giảm và không được tăng. Khi giá trị biến đếm giảm xuống 0, thread X sẽ được thực thi. Giá trị khởi tạo của biến đếm được chỉ định thông qua hàm khởi tạo: CountDownLatch(int count).

Mỗi khi một thread A hoàn thành, phương thức countDown() sẽ được gọi để giảm biến đếm xuống 1. Ngược lại, phương thức await() sẽ được gọi để block thread cho đến khi biến đếm giảm xuống 0. Khi đó, thread X sẽ bắt đầu thực thi.

Ví dụ sử dụng CountDownLatch:

java Copy
public class MainTask implements Runnable {
    @Override
    public void run() {
        System.out.println("Start main task...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Done main task!");
    }
}

public class SubTask implements Runnable {
    private CountDownLatch countDownLatch;

    public SubTask(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println("Start sub task...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Done sub task!");
        countDownLatch.countDown();
    }
}

public class Test {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(new SubTask(countDownLatch));
        executorService.submit(new SubTask(countDownLatch));
        executorService.submit(new SubTask(countDownLatch));

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(countDownLatch.getCount());
        executorService.submit(new MainTask());
        executorService.shutdown();
    }
}

Kết quả thực thi:

Copy
Start sub task...
Start sub task...
Start sub task...
Done sub task!
Done sub task!
Done sub task!
0
Start main task...
Done main task!

2. CyclicBarrier

Nguyên lý hoạt động

Lớp CyclicBarrier dùng để cho phép các thread đợi nhau tại một điểm chặn (hay còn gọi là barrier) trước khi tiếp tục thực thi. Điều thú vị là CyclicBarrier có thể tái sử dụng nhiều lần sau khi đã đạt đến barrier và được giải phóng.

Giá trị khởi tạo tối đa cho số lượng thread có thể tiếp cận barrier được chỉ định thông qua hàm khởi tạo: CyclicBarrier(int parties). Khi các thread hoàn thành các công việc của mình, chúng sẽ gọi phương thức await() để tham gia vào quá trình đợi. Khi tất cả các thread đã await(), mã lệnh sau await() trong mỗi thread sẽ tiếp tục thực hiện.

Bạn cũng có thể chỉ định một hành động sẽ được thực thi khi tất cả các thread đến barrier thông qua hàm khởi tạo: CyclicBarrier(int parties, Runnable barrierAction).

Ví dụ sử dụng CyclicBarrier:

java Copy
public class Service implements Runnable {
    private String serviceName;
    private CyclicBarrier cyclicBarrier;

    public Service(String serviceName, CyclicBarrier cyclicBarrier) {
        this.serviceName = serviceName;
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        System.out.println("Service " + serviceName + " started...");
        try {
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println("Service " + serviceName + " was available to accept request");
    }
}

public class Test {
    private static final int ENVIRONMENTS = 3;
    private static final int SERVICES = 3;

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(SERVICES, () -> {
            System.out.println("Done one environment");
        });

        ExecutorService executor = Executors.newFixedThreadPool(ENVIRONMENTS);
        for (int i = 1; i <= ENVIRONMENTS; i++) {
            executor.submit(new Service("A" + i, cyclicBarrier));
            executor.submit(new Service("B" + i, cyclicBarrier));
            executor.submit(new Service("C" + i, cyclicBarrier));
        }

        executor.shutdown();
    }
}

Kết quả thực thi:

Copy
Service A1 started...
Service C1 started...
Service B1 started...
Done one environment
Service B1 was available to accept request
Service A1 was available to accept request
Service A2 started...
Service B2 started...
Service C1 was available to accept request
Service C2 started...
Done one environment
Service C2 was available to accept request
Service A2 was available to accept request
Service B2 was available to accept request
Service C3 started...
Service A3 started...
Service B3 started...
Done one environment
Service B3 was available to accept request
Service C3 was available to accept request
Service A3 was available to accept request

Kết luận

Tổng kết lại, CountDownLatchCyclicBarrier là hai lớp quan trọng trong Java giúp cho việc đồng bộ hóa các luồng trở nên hiệu quả hơn. CountDownLatch được sử dụng khi bạn cần đợi cho nhiều tác vụ hoàn thành trước khi thực hiện một tác vụ khác, trong khi CyclicBarrier được áp dụng khi các thread cần phải đợi nhau tại một điểm nào đó trước khi tiếp tục. Việc lựa chọn giữa CountDownLatchCyclicBarrier tùy thuộc vào yêu cầu cụ thể của ứng dụng và cách thức đồng bộ hóa mà bạn mong muốn áp dụng.
source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào