Java中的J.U.C并发工具类详解
字数 1284 2025-11-04 20:48:20
Java中的J.U.C并发工具类详解
一、J.U.C概述
J.U.C(java.util.concurrent)是Java提供的并发编程工具包,包含解决并发问题的三大类组件:
- 原子类(Atomic) - 线程安全的原子操作类
- 锁机制(Locks) - 比synchronized更灵活的锁
- 并发集合(Collections) - 线程安全的集合容器
- 线程池(Executor) - 线程管理和调度
- 同步工具(Tools) - 控制线程执行的工具类
二、CountDownLatch(倒计时门闩)
-
核心作用:让一个或多个线程等待其他线程完成操作
-
实现原理:
- 内部维护一个计数器,初始化时设置等待的线程数
- 每个线程完成时调用countDown()使计数器减1
- 当计数器为0时,等待的线程被唤醒
-
代码示例:
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3); // 初始计数器为3
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 完成任务");
latch.countDown(); // 计数器减1
}, "线程" + i).start();
}
latch.await(); // 主线程等待,直到计数器为0
System.out.println("所有线程完成任务,主线程继续执行");
}
}
三、CyclicBarrier(循环屏障)
-
核心作用:让一组线程相互等待,达到共同屏障点后再继续执行
-
与CountDownLatch的区别:
- CountDownLatch是一次性的,CyclicBarrier可重复使用
- CountDownLatch由主线程等待,CyclicBarrier是线程间相互等待
-
代码示例:
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程到达屏障,执行屏障动作");
});
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 到达屏障");
barrier.await(); // 等待其他线程
System.out.println(Thread.currentThread().getName() + " 继续执行");
} catch (Exception e) {
e.printStackTrace();
}
}, "线程" + i).start();
}
}
}
四、Semaphore(信号量)
-
核心作用:控制同时访问特定资源的线程数量
-
两种模式:
- 公平模式:按申请顺序获取许可
- 非公平模式:抢占式获取许可
-
代码示例:
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可
System.out.println(Thread.currentThread().getName() + " 获取资源");
Thread.sleep(2000); // 模拟资源使用
System.out.println(Thread.currentThread().getName() + " 释放资源");
semaphore.release(); // 释放许可
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "线程" + i).start();
}
}
}
五、Exchanger(交换器)
-
核心作用:用于两个线程间交换数据
-
执行流程:
- 线程A执行exchange()方法后阻塞,等待线程B
- 线程B执行exchange()方法后,双方交换数据并继续执行
-
代码示例:
public class ExchangerDemo {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
new Thread(() -> {
try {
String dataA = "数据A";
System.out.println("线程A发送: " + dataA);
String result = exchanger.exchange(dataA);
System.out.println("线程A收到: " + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
String dataB = "数据B";
System.out.println("线程B发送: " + dataB);
String result = exchanger.exchange(dataB);
System.out.println("线程B收到: " + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
六、Phaser(阶段器)
-
核心作用:更灵活的可重用同步屏障,支持动态调整参与线程数
-
核心概念:
- 阶段(Phase):从0开始编号,完成所有线程后阶段号递增
- 注册(Register):动态增加或减少参与线程数
-
代码示例:
public class PhaserDemo {
public static void main(String[] args) {
Phaser phaser = new Phaser(3) { // 初始3个参与线程
@Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("阶段 " + phase + " 完成");
return registeredParties == 0; // 返回true终止Phaser
}
};
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 完成阶段0");
phaser.arriveAndAwaitAdvance(); // 等待其他线程
System.out.println(Thread.currentThread().getName() + " 完成阶段1");
phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister(); // 完成任务并注销
}, "线程" + i).start();
}
}
}
七、工具类对比总结
| 工具类 | 核心功能 | 可重用性 | 特点 |
|---|---|---|---|
| CountDownLatch | 等待指定数量任务完成 | 否 | 一次性使用,主线程等待 |
| CyclicBarrier | 线程间相互等待 | 是 | 可重复使用,支持屏障动作 |
| Semaphore | 控制资源访问数量 | 是 | 支持公平/非公平模式 |
| Exchanger | 线程间数据交换 | 是 | 仅支持两个线程交换 |
| Phaser | 分阶段任务同步 | 是 | 最灵活,支持动态调整 |
八、使用场景分析
- CountDownLatch:主线程等待所有子任务完成
- CyclicBarrier:多线程计算,合并计算结果
- Semaphore:数据库连接池限流
- Exchanger:两个线程间数据校对
- Phaser:复杂的多阶段任务协调
这些工具类提供了比wait/notify更高级的线程协作方式,能够简化复杂并发场景的开发。