悠悠楠杉
JUC并发工具类实战指南:提升Java并发编程效率
一、JUC工具类概览
在Java多线程开发中,单纯使用基础的synchronized和volatile已难以应对复杂场景。JUC包提供的并发工具类就像多线程编程中的"瑞士军刀",它们通过更高层次的抽象,解决了线程同步、资源控制等核心问题。这些工具类分为三大类型:
- 同步控制器(如CountDownLatch)
- 并发容器(如ConcurrentHashMap)
- 原子变量类(如AtomicInteger)
本文重点讲解最常用的同步控制器类。
二、CountDownLatch:多线程任务协调器
核心原理
CountDownLatch相当于多线程环境下的"倒计时门闩",初始化时设置计数器值,当计数器归零时,阻塞线程才会继续执行。
典型场景
- 主线程等待多个子线程完成初始化
- 并行任务完成后触发汇总操作
java
// 电商订单支付场景示例
public class OrderPaymentService {
private static final int THREAD_COUNT = 3;
public void processPayment() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
// 模拟并发支付操作
for (int i = 0; i < THREAD_COUNT; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 开始支付");
Thread.sleep(new Random().nextInt(1000));
System.out.println(Thread.currentThread().getName() + " 支付完成");
latch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
latch.await();
System.out.println("所有支付操作已完成,开始库存扣减");
}
}
注意事项:
- 计数器不可重置,用完即废
- 建议设置超时时间的await(long timeout, TimeUnit unit)
三、CyclicBarrier:可复用的线程屏障
与CountDownLatch的区别
CyclicBarrier更像"循环使用的集合点",所有线程到达屏障后才会继续执行,且计数器可以重置。
适用场景
- 多阶段任务处理
- 数据分片计算后合并
java
// 银行对账系统案例
public class ReconciliationSystem {
private static final int PARTIES = 4;
public void startReconciliation() {
CyclicBarrier barrier = new CyclicBarrier(PARTIES,
() -> System.out.println("所有分行对账完成,开始总账核对"));
for (int i = 1; i <= PARTIES; i++) {
new Thread(new BranchReconTask(barrier, "分行"+i)).start();
}
}
class BranchReconTask implements Runnable {
private final CyclicBarrier barrier;
private final String branchName;
// 构造方法省略...
@Override
public void run() {
try {
System.out.println(branchName + "开始本地对账");
Thread.sleep(200 + new Random().nextInt(800));
System.out.println(branchName + "对账完成,等待其他分行");
barrier.await();
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}
}
}
关键点:
- 构造时可设置屏障动作(Runnable)
- 调用reset()方法会触发BrokenBarrierException
四、Semaphore:资源访问控制器
核心作用
控制同时访问特定资源的线程数量,相当于"流量阀"。
真实应用
- 数据库连接池管理
- 限流场景
java
// 停车场管理系统模拟
public class ParkingLot {
private static final int PARKINGSPACES = 5;
private final Semaphore semaphore = new Semaphore(PARKINGSPACES);
public boolean parkCar(String carId) {
if (semaphore.tryAcquire()) {
System.out.println(carId + " 成功停车");
return true;
}
System.out.println(carId + " 等待空位...");
return false;
}
public void leaveCar(String carId) {
semaphore.release();
System.out.println(carId + " 已离开,当前空位:" + semaphore.availablePermits());
}
}
进阶用法:
- 公平模式(FairSync)
- 批量获取许可证(acquire(int permits))
五、综合对比与选型建议
| 工具类 | 重用性 | 主要用途 | 典型场景 |
|----------------|---------|-----------------------|--------------------------|
| CountDownLatch | 一次性 | 等待事件完成 | 系统启动初始化 |
| CyclicBarrier | 可循环 | 线程集合等待 | 并行计算分阶段处理 |
| Semaphore | 可重复 | 控制资源访问 | 连接池/限流 |
性能优化提示:
1. 优先尝试tryAcquire而非阻塞获取
2. 合理设置超时时间避免死锁
3. 考虑使用Phaser替代复杂屏障场景
掌握这些工具类的本质区别,才能在分布式锁设计、系统压测等场景中灵活运用。建议在IDE中实际运行文中的代码示例,通过调试模式观察线程状态变化,这将比单纯阅读获得更深的理解。