面试题:你使用过哪些 Java 并发工具类?

在 Java 并发编程中,我使用过以下常用的并发工具类(均属于 java.util.concurrent 包),它们各自适用于不同的并发控制和线程协作场景:


✅ 1. CountDownLatch(倒计数锁存器)

📌 使用场景:

  • 主线程等待多个子线程完成后再继续执行。
  • 资源初始化完成后通知主线程启动。

📌 核心方法:

  • await():阻塞当前线程直到计数器归零。
  • countDown():计数器减 1。

📌 特点:

  • 一次性使用,计数器不可重置。
  • 适用于一次性等待多个线程完成的场景。

示例代码:

CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 执行任务
        latch.countDown();
    }).start();
}
latch.await(); // 主线程等待
System.out.println("所有子线程已完成");

✅ 2. CyclicBarrier(循环屏障)

📌 使用场景:

  • 多个线程互相等待,直到都到达某个屏障点后再一起继续执行。
  • 多阶段并行计算,例如并行排序、分阶段任务。

📌 核心方法:

  • await():线程到达屏障点并等待。
  • reset():重置屏障,进入下一轮同步。

📌 特点:

  • 可重复使用,支持多轮同步。
  • 可选执行一个“屏障动作”(Barrier Action)。

示例代码:

CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程已到达屏障点"));
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 执行任务
        barrier.await();
    }).start();
}

✅ 3. Semaphore(信号量)

📌 使用场景:

  • 控制同时访问的线程数量(如连接池、限流)。
  • 实现互斥锁(许可数为 1)。
  • 生产者-消费者模型中控制缓冲区的访问。

📌 核心方法:

  • acquire():获取许可,阻塞直到有空闲。
  • release():释放许可。

📌 特点:

  • 可设置为公平或非公平模式
  • 支持多次获取与释放

示例代码:

Semaphore semaphore = new Semaphore(3); // 同时最多3个线程访问
semaphore.acquire();
try {
    // 使用资源
} finally {
    semaphore.release();
}

✅ 4. Exchanger(线程间交换器)

📌 使用场景:

  • 两个线程之间交换数据(如双缓冲、流水线处理)。

📌 核心方法:

  • exchange(V data):线程等待另一个线程调用此方法,交换数据。

📌 特点:

  • 用于两个线程间的数据交换
  • 适用于双缓冲、流水线、数据同步等场景。

示例代码:

Exchanger<String> exchanger = new Exchanger<>();
new Thread(() -> {
    String data = "from thread1";
    try {
        String other = exchanger.exchange(data);
        System.out.println("收到:" + other);
    } catch (InterruptedException e) { ... }
}).start();

new Thread(() -> {
    String data = "from thread2";
    try {
        String other = exchanger.exchange(data);
        System.out.println("收到:" + other);
    } catch (InterruptedException e) { ... }
}).start();

✅ 5. Phaser(阶段同步器)

📌 使用场景:

  • 多阶段任务同步,支持动态注册线程。
  • 替代 CountDownLatchCyclicBarrier,功能更灵活。

📌 核心方法:

  • arrive():线程到达阶段点。
  • arriveAndAwaitAdvance():到达并等待其他线程完成当前阶段。
  • register():动态注册线程。

📌 特点:

  • 支持多阶段同步
  • 支持动态添加/移除线程
  • 更灵活,适用于复杂任务划分。

✅ 6. CompletableFuture(异步任务编排)

📌 使用场景:

  • 异步编程、任务链式调用、组合多个异步任务结果。
  • 替代传统的 Future 和回调地狱。

📌 核心方法:

  • supplyAsync() / runAsync():异步执行任务。
  • thenApply() / thenAccept() / thenRun():任务链式调用。
  • thenCombine() / allOf() / anyOf():组合多个任务。

📌 特点:

  • 支持异步非阻塞编程
  • 支持任务组合与异常处理
  • 是现代 Java 并发编程中非常强大的工具。

✅ 7. ReentrantLock(可重入锁)

📌 使用场景:

  • 替代 synchronized,实现更灵活的锁机制。
  • 尝试加锁、超时加锁、尝试获取锁失败时执行其他逻辑。

📌 核心方法:

  • lock() / unlock():加锁与释放锁。
  • tryLock():尝试加锁,不阻塞。

📌 特点:

  • 支持公平锁与非公平锁
  • 支持尝试加锁、超时机制
  • 提供更细粒度的锁控制。

✅ 8. ReentrantReadWriteLock(读写锁)

📌 使用场景:

  • 多线程读多写少的场景(如缓存、配置管理)。
  • 读操作并发执行,写操作独占执行。

📌 核心方法:

  • readLock() / writeLock():获取读锁或写锁。

📌 特点:

  • 读共享,写独占。
  • 提高并发性能,适用于读多写少的场景。

✅ 9. BlockingQueue(阻塞队列)

📌 使用场景:

  • 生产者-消费者模型中的线程间通信。
  • 线程池任务队列。

📌 常见实现类:

  • ArrayBlockingQueue:有界队列。
  • LinkedBlockingQueue:无界队列。
  • SynchronousQueue:容量为 0,生产者必须等待消费者。

📌 核心方法:

  • put() / take():阻塞式插入与取出。
  • offer() / poll():非阻塞方式。

✅ 10. ThreadLocalRandom / ForkJoinPool / CompletableFuture

  • ThreadLocalRandom:线程安全的随机数生成器。
  • ForkJoinPool:分治任务调度器,适用于并行任务拆分。
  • CompletableFuture:异步任务编排工具(前面已介绍)。

📌 总结对比表

工具类主要用途是否可重用是否支持超时是否公平适用场景
CountDownLatch等待多个线程完成主线程等待子线程
CyclicBarrier多线程到达屏障点后继续执行多阶段任务同步
Semaphore控制并发资源访问可选资源池、限流、互斥
Exchanger两个线程交换数据数据同步、双缓冲
Phaser多阶段任务同步,支持动态线程多阶段并行任务
ReentrantLock可重入锁可选替代 synchronized,更灵活的锁控制
ReentrantReadWriteLock读写分离锁可选读多写少的并发场景
BlockingQueue线程间通信,任务队列生产者-消费者模型
CompletableFuture异步任务编排异步编程、任务链式调用
THE END
喜欢就支持一下吧
点赞14 分享