CountDownLatch,Semaphore,CyclicBarrier使用案例

发布时间:2024年01月02日

CountDownLatch是Java中的一个同步辅助工具类,它可以让一个或多个线程等待其他线程完成操作后再继续执行。CountDownLatch通过一个计数器来实现,计数器的初始值可以指定,当计数器的值变为0时,所有等待的线程就会被唤醒继续执行。

通常用于以下两种场景:一个线程等待多个其他线程执行完毕后再继续执行;?多个线程等待某个共同事件的发生后再继续执行。

CountDownLatch

??案例一


/**
 * CountDownLatch使用案例,配合await()方法使用,线程执行完毕会阻塞在await()这,直至所有线程执行完毕
 */
public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int numThreads = 3;
        CountDownLatch latch = new CountDownLatch(numThreads);

        for (int i = 0; i < numThreads; i++) {
            Thread thread = new Thread(new Worker(latch));
            thread.start();
        }

        latch.await(); // 主线程等待所有子线程完成任务

        System.out.println("All threads have completed their tasks. Main thread can continue.");
    }

    static class Worker implements Runnable {
        private CountDownLatch latch;

        public Worker(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                // 模拟子线程执行任务
                Thread.sleep((long) (Math.random() * 1000));
                System.out.println("Task completed by thread: " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                latch.countDown(); // 子线程完成任务后调用countDown减少计数器
            }
        }
    }
}

输出结果:

Task completed by thread: Thread-2
Task completed by thread: Thread-0
Task completed by thread: Thread-1
All threads have completed their tasks. Main thread can continue.

?案例二


/**
 * 使用CountDownLatch完成多个游戏玩家进度条的加载
 * 直到所有玩家进度条加载完毕,游戏就可以启动了
 */
public class ProgressBarWithCountDownLatch {
    public static void main(String[] args) throws InterruptedException {
        int numThreads = 3;
        CountDownLatch latch = new CountDownLatch(numThreads);

        for (int i = 0; i < numThreads; i++) {
            Thread thread = new Thread(new Task(latch, "Thread-" + i));
            thread.start();
        }

        latch.await(); // 等待所有线程加载完毕

        System.out.println("All progress bars have completed. Main thread can continue.");
    }

    static class Task implements Runnable {
        private CountDownLatch latch;
        private String threadName;

        public Task(CountDownLatch latch, String threadName) {
            this.latch = latch;
            this.threadName = threadName;
        }

        @Override
        public void run() {
            System.out.println("Thread " + threadName + " started loading progress bar");
            for (int i = 0; i <= 100; i += 10) {
                updateProgressBar(threadName, i);
                try {
                    Thread.sleep((long) (20 * Math.random()));   // 模拟加载进度
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Thread " + threadName + " finished loading progress bar");
            latch.countDown(); // 减少计数器
        }

        static void updateProgressBar(String threadName, int progress) {
            // 更新进度条的显示
            System.out.println("Thread " + threadName + " - Progress: " + progress + "%");
        }
    }
}

输出结果

Thread Thread-0 started loading progress bar
Thread Thread-2 started loading progress bar
Thread Thread-2 - Progress: 0%
Thread Thread-1 started loading progress bar
Thread Thread-0 - Progress: 0%
Thread Thread-1 - Progress: 0%
Thread Thread-2 - Progress: 10%
Thread Thread-2 - Progress: 20%
Thread Thread-0 - Progress: 10%
Thread Thread-1 - Progress: 10%
Thread Thread-2 - Progress: 30%
Thread Thread-1 - Progress: 20%
Thread Thread-0 - Progress: 20%
Thread Thread-1 - Progress: 30%
Thread Thread-1 - Progress: 40%
Thread Thread-2 - Progress: 40%
Thread Thread-0 - Progress: 30%
Thread Thread-2 - Progress: 50%
Thread Thread-0 - Progress: 40%
Thread Thread-0 - Progress: 50%
Thread Thread-1 - Progress: 50%
Thread Thread-1 - Progress: 60%
Thread Thread-2 - Progress: 60%
Thread Thread-2 - Progress: 70%
Thread Thread-0 - Progress: 60%
Thread Thread-0 - Progress: 70%
Thread Thread-1 - Progress: 70%
Thread Thread-1 - Progress: 80%
Thread Thread-2 - Progress: 80%
Thread Thread-2 - Progress: 90%
Thread Thread-0 - Progress: 80%
Thread Thread-2 - Progress: 100%
Thread Thread-0 - Progress: 90%
Thread Thread-1 - Progress: 90%
Thread Thread-2 finished loading progress bar
Thread Thread-0 - Progress: 100%
Thread Thread-1 - Progress: 100%
Thread Thread-0 finished loading progress bar
Thread Thread-1 finished loading progress bar
All progress bars have completed. Main thread can continue.

Process finished with exit code 0

Semaphore

Semaphore是Java中的一个同步工具类,它可以控制同时访问特定资源的线程数量。Semaphore维护了一组许可,线程可以通过acquire()方法获取许可,通过release()方法释放许可。当许可数达到上限时,后续请求许可的线程会被阻塞,直到有其他线程释放许可。 Semaphore通常用于以下场景: 控制同时访问的线程数量,如连接池、资源池等;限流,控制系统的并发访问量。

?案例一:使用acquire()

/**
 * Semaphore使用案例
 * 一开始设置了semaphore = 2, 即最大同时存在的线程为2
 * 在本次案例中我们开启了5个线程,执行任务
 * 每次使用需要调用acquire()方法,如果获取成功,semaphore-1,然后往下执行;执行完毕semaphore+1
 * 否则会阻塞,直到有其他线程释放了semaphore
 */
public class SemaphoreExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // 允许同时访问打印机的线程数量为2

        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + Thread.currentThread().getName() +  " is waiting to access the printer");
                    semaphore.acquire(); // 获取许可
                    System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + Thread.currentThread().getName() + " is printing");
                    Thread.sleep(2000); // 假设打印需要2秒钟
                    System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + Thread.currentThread().getName() + " has finished printing");
                    semaphore.release(); // 释放许可
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start(); // 有5个线程想要访问打印机
        }
    }
}

输出结果

11:30:46 Thread-1 is waiting to access the printer
11:30:46 Thread-2 is waiting to access the printer
11:30:46 Thread-4 is waiting to access the printer
11:30:46 Thread-1 is printing
11:30:46 Thread-0 is waiting to access the printer
11:30:46 Thread-3 is waiting to access the printer
11:30:46 Thread-2 is printing
11:30:48 Thread-1 has finished printing
11:30:48 Thread-2 has finished printing
11:30:48 Thread-4 is printing
11:30:48 Thread-0 is printing
11:30:50 Thread-0 has finished printing
11:30:50 Thread-4 has finished printing
11:30:50 Thread-3 is printing
11:30:52 Thread-3 has finished printing

Process finished with exit code 0

案例二:使用tryAcquire()

/**
 * Semaphore使用tryacquire()方法,如果没有semaphore,则会直接返回false,而不会被阻塞,等待其他线程释放资源
 * 
 */
public class SemaphoreExampleTryAcquire {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // 允许同时访问打印机的线程数量为2

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                if (semaphore.tryAcquire()) {
                    try {
                        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + Thread.currentThread().getName() + " is printing");
                        Thread.sleep(2000); // 假设打印需要2秒钟
                        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " + Thread.currentThread().getName() + " has finished printing");
                        semaphore.release(); // 释放许可
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " " +  Thread.currentThread().getName() + " failed to acquire the semaphore");
                }
            }).start(); // 有5个线程想要访问打印机
        }
    }
}

输出结果

11:32:58 Thread-4 failed to acquire the semaphore
11:32:58 Thread-2 failed to acquire the semaphore
11:32:58 Thread-3 failed to acquire the semaphore
11:32:58 Thread-0 is printing
11:32:58 Thread-1 is printing
11:33:00 Thread-0 has finished printing
11:33:00 Thread-1 has finished printing

Process finished with exit code 0

CyclicBarrier使用案例

CyclicBarrier是Java中的一个同步辅助工具类,它允许一组线程互相等待,直到所有线程都达到某个公共屏障点,然后再继续执行。CyclicBarrier的特点是可以循环使用,一旦所有线程都到达屏障点,屏障就会打开,所有线程会被释放,并且CyclicBarrier可以被重置以再次使用。 CyclicBarrier通常用于以下场景: 将多个线程分成多个阶段执行,每个阶段的线程都必须等待其他线程完成后才能继续执行。 同时开始执行多个任务,等所有任务都准备好后再开始执行。


/**
 * CyclicBarrier使用案例,线程执行任务完成后会停留在await(),
 * 直到所有线程执行任务完毕,才会被放行;
 * 接着就会继续执行其他的任务
 */
public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numThreads, () -> {
            System.out.println("All threads have reached the barrier. Starting the next phase.");
        });

        for (int i = 0; i < numThreads; i++) {
            Thread worker = new Thread(new Worker(barrier, "Worker-" + i));
            worker.start();
        }
    }

    static class Worker implements Runnable {
        private CyclicBarrier barrier;
        private String workerName;

        public Worker(CyclicBarrier barrier, String workerName) {
            this.barrier = barrier;
            this.workerName = workerName;
        }

        @Override
        public void run() {
            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " Worker " + workerName + " is working");
            try {
                Thread.sleep((long) (Math.random() * 2000)); // 模拟不同的工作时间
                System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " Worker " + workerName + " has reached the barrier");
                barrier.await(); // 等待所有线程到达屏障
                System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) + " Worker " + workerName + " is continuing to work");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

输出结果

12:45:40 Worker Worker-1 is working
12:45:40 Worker Worker-2 is working
12:45:40 Worker Worker-0 is working
12:45:40 Worker Worker-0 has reached the barrier
12:45:40 Worker Worker-1 has reached the barrier
12:45:42 Worker Worker-2 has reached the barrier
All threads have reached the barrier. Starting the next phase.
12:45:42 Worker Worker-2 is continuing to work
12:45:42 Worker Worker-0 is continuing to work
12:45:42 Worker Worker-1 is continuing to work

Process finished with exit code 0

总结

总的来说,CountDownLatch用于等待其他线程的完成,Semaphore用于控制并发线程数量,CyclicBarrier用于多阶段任务的协作。

文章来源:https://blog.csdn.net/xuan__xia/article/details/135337730
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。