原创

java面试题-CountDownLatch 和 CyclicBarrier 的区别?

引言

在并发编程中,实现线程间的协调和同步是一个重要的主题。Java提供了多个并发工具类来帮助开发者更容易地实现这些目标。本教程将深入探讨两个常用的并发工具类:CountDownLatch和CyclicBarrier。我们将详细解释它们的概念、用法,并通过示例代码演示如何正确使用它们。通过学习本教程,读者将更好地理解这两个工具类的区别和适用场景。

1. CountDownLatch 的概念和用法

1.1 概念

CountDownLatch是Java并发工具包中的一个类,它允许一个或多个线程等待其他线程完成各自工作之后再继续执行。它通过一个计数器实现,计数器的初始值为线程的数量。每个线程完成自己的任务后,计数器减一。当计数器的值为0时,表示所有线程都已完成任务,等待的线程将恢复执行。

1.2 示例代码

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(3);

        Runnable worker = () -> {
            try {
                // 模拟线程执行任务
                Thread.sleep((long) (Math.random() * 5000));
                System.out.println("任务完成");
                // 计数器减一
                latch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        // 创建三个线程并启动
        new Thread(worker).start();
        new Thread(worker).start();
        new Thread(worker).start();

        try {
            System.out.println("等待所有任务完成...");
            // 主线程等待计数器为0
            latch.await();
            System.out.println("所有任务已完成,继续执行主线程");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

解释示例代码:

  • 主线程创建了一个CountDownLatch,初始值为3,表示有三个线程需要等待。
  • 每个工作线程在执行完任务后,调用latch.countDown()减小计数器。
  • 主线程通过latch.await()等待计数器为0,一旦为0,表示所有任务完成,主线程继续执行。

2. CyclicBarrier 的概念和用法

2.1 概念

CyclicBarrier也是Java并发工具包中的一个类,它允许一组线程互相等待,直到到达某个公共屏障点。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时CyclicBarrier很有用。因为该Barrier在释放等待线程后可以重用,所以称它为循环的屏障。

2.2 示例代码

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        final int numThreads = 3;
        final CyclicBarrier barrier = new CyclicBarrier(numThreads);

        Runnable worker = () -> {
            try {
                // 模拟线程执行任务
                Thread.sleep((long) (Math.random() * 5000));
                System.out.println("已到达屏障点");
                // 等待其他线程到达屏障点
                barrier.await();
                System.out.println("继续执行后续任务");
            } catch (Exception e) {
                e.printStackTrace();
            }
        };

        // 创建三个线程并启动
        new Thread(worker).start();
        new Thread(worker).start();
        new Thread(worker).start();
    }
}

解释示例代码:

  • 主线程创建了一个CyclicBarrier,设置等待的线程数量为3。
  • 每个工作线程在执行完任务后,调用barrier.await()等待其他线程到达屏障点。
  • 当所有线程都到达屏障点后,它们将继续执行后续任务。

3. CountDownLatch 和 CyclicBarrier 的区别

3.1 相同点

  • 都是用于多个线程之间的同步。
  • 都使用计数器的概念,通过计数器的变化来实现线程之间的等待和通知。

3.2 不同点

  • 作用不同:

    • CountDownLatch的作用是允许1或N个线程等待其他线程完成执行。
    • CyclicBarrier的作用是允许N个线程相互等待。
  • 计数器重置:

    • CountDownLatch的计数器无法被重置,一旦计数器减为0,无法再次使用。
    • CyclicBarrier的计数器可以被重置,因此它可以被循环使用。

4. 总结

通过学习本教程,我们深入理解了CountDownLatch和CyclicBarrier这两个并发工具类。我们通过示例代码演示了它们的基本用法,详细解释了它们的概念和区别。在实际编程中,根据具体需求选择合适的工具类是至关重要的。
希望读者通过本教程能够更好地掌握这两个并发工具类的用法,提升多线程编程的技能。

正文到此结束
本文目录