CountDownLatch
、Semaphore
和CyclicBarrier
?粉丝提问:
在Java并发编程中,
CountDownLatch
、Semaphore
和CyclicBarrier
是常见的同步工具。它们在JDK 8、17和21中有何差异?如何正确使用它们?
本文将为你全面解析这些工具类的原理、使用方法及其在不同Java版本中的优化点,助你轻松解决并发任务中的同步问题。
CountDownLatch
作用:允许一个线程等待多个线程完成任务后再继续执行。 典型场景:启动多个线程并等待它们完成初始化。
Semaphore
作用:控制同时访问特定资源的线程数量。 典型场景:限制访问某个资源的并发线程数,例如数据库连接池。
CyclicBarrier
作用:让一组线程到达同步点后再一起继续执行。 典型场景:实现多线程协同工作,例如并行任务分块计算。
工具类 | JDK 8 | JDK 17 | JDK 21 |
---|---|---|---|
CountDownLatch | 基本功能实现 | 性能优化:减少竞争锁 | 集成虚拟线程更高效 |
Semaphore | 基础信号量实现 | 增加公平性支持 | 与虚拟线程兼容性提升 |
CyclicBarrier | 基础同步实现 | 增强异常处理 | 性能提升:通过虚拟线程实现大规模并发 |
CountDownLatch
示例:多线程初始化import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int threadCount = 3;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 初始化完成");
latch.countDown(); // 每个线程完成后减少计数
}).start();
}
latch.await(); // 等待所有线程完成
System.out.println("所有线程初始化完成,继续执行主任务");
}
}
Semaphore
示例:限制资源访问import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2); // 允许同时访问的线程数为2
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可
System.out.println(Thread.currentThread().getName() + " 获取资源");
Thread.sleep(1000); // 模拟资源使用
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // 释放许可
System.out.println(Thread.currentThread().getName() + " 释放资源");
}
}).start();
}
}
}
CyclicBarrier
示例:并发任务分块计算import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
int parties = 3;
CyclicBarrier barrier = new CyclicBarrier(parties, () -> System.out.println("所有线程已到达屏障,开始下一步"));
for (int i = 0; i < parties; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 执行任务");
Thread.sleep(1000); // 模拟任务执行
barrier.await(); // 等待其他线程
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
在JDK 21中,虚拟线程的引入显著提升了上述工具类的并发性能:
CountDownLatch
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
public class VirtualThreadCountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int threadCount = 10;
CountDownLatch latch = new CountDownLatch(threadCount);
var executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < threadCount; i++) {
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 虚拟线程任务完成");
latch.countDown();
});
}
latch.await();
System.out.println("所有虚拟线程任务完成");
executor.close();
}
}
Q:虚拟线程是否完全替代传统线程? A:虚拟线程在高并发任务中表现出色,但对于重计算任务,仍需传统线程池支持。
Q:CyclicBarrier 与 Semaphore 的选择标准是什么? A:CyclicBarrier 适用于任务协同,Semaphore 用于资源访问限制。根据具体场景选择。
趋势展望: JDK 21中的虚拟线程将彻底改变并发编程方式: