在Java中,为了解决多线程并发执行的问题,提供了一些并发工具类,其中最常用的三个是CountDownLatch
、CyclicBarrier
和Semaphore
。这些工具类为我们提供了方便且高效的并发编程解决方案。
CountDownLatch(倒计时门栓)
CountDownLatch
是一种能够阻塞线程直到某个事件完成的同步辅助类。它需要一个初始计数值,每当一个线程完成了某个事件,计数值就会减1。当计数值变为0时,所有在CountDownLatch
上阻塞的线程将被释放。
使用CountDownLatch
的典型场景是:等待多个子线程完成,再进行主线程的工作。例如,你想要统计某个任务需要的所有时间,你可以创建一个CountDownLatch
,然后在每个子线程的工作完成时调用countDown()
方法,主线程在await()
方法上等待,直到所有子线程完成。
以下是一个简单的示例代码:
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
// 子线程的工作
latch.countDown();
}).start();
}
try {
latch.await();
// 所有子线程工作完成,进行主线程的工作
} catch (InterruptedException e) {
e.printStackTrace();
}
CyclicBarrier(循环栅栏)
CyclicBarrier
是一种同步辅助类,它允许一组线程互相等待,直到所有线程都达到某一状态,然后这一组线程才会继续执行。和CountDownLatch
不同,CyclicBarrier
的计数值是可以重置的,当计数值达到初始值时,所有等待的线程都会继续执行。
使用CyclicBarrier
的典型场景是:将一个任务分成N个子任务,只有这N个子任务都完成时,才继续进行下一阶段的任务。工作线程可以在Barrier上等待,直到线程都达到Barrier时,线程可以向下运行。
以下是一个简单的示例代码:
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
// 子线程都达到Barrier后,执行的方法
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
// 子线程的工作
barrier.await();
}).start();
}
Semaphore(信号量)
Semaphore
是一种用来控制同时访问特定资源的线程数量的同步辅助类。它维护了一个许可证计数器,线程可以通过调用acquire()
方法来获取许可证,用完后再调用release()
方法归还许可证。
使用Semaphore
的典型场景是:限制对某个资源的并发访问量。例如,你想要控制同时访问某个数据库的线程数量,你可以创建一个Semaphore
并设置许可证数量为最大并发数,每个线程在访问数据库之前先调用acquire()
方法获取许可证,访问完后再调用release()
方法归还许可证。
以下是一个简单的示例代码:
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire();
// 线程的工作
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
总结:通过CountDownLatch
、CyclicBarrier
和Semaphore
这三种并发工具类,我们可以更加方便地实现多线程并发编程。CountDownLatch
用于等待一组线程的完成,CyclicBarrier
用于等待多个线程达到某一状态,Semaphore
用于控制同时访问某个资源的线程数量。在实际应用中,我们根据具体的需求选择合适的并发工具类来解决问题,以提高程序的性能和效率。
本文来自极简博客,作者:代码魔法师,转载请注明原文链接:Java中的并发工具类:CountDownLatch、CyclicBarrier与Semaphore