Java线程并发工具类CountDownLatch原理及用法

2025-05-29 0 62

一、CountDownLatch

【1】CountDownLatch是什么?

CountDownLatch,英文翻译为倒计时锁存器,是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或

多个线程一直等待。

闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:

  • 确保某个计算在其需要的所有资源都被初始化之后才继续执行;
  • 确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
  • 等待直到某个操作所有参与者都准备就绪再继续执行;

CountDownLatch有一个正数计数器,countDown()方法对计数器做减操作,await()方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。

闭锁(倒计时锁)主要用来保证完成某个任务的先决条件满足。是一个同步工具类,用来协调多个线程之间的同步。这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。

【2】CountDownLatch的两种典型用法

①某一线程在开始运行前等待n个线程执行完毕。

将 CountDownLatch 的计数器初始化为n :new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

②实现多个线程开始执行任务的最大并行性。

注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的 CountDownLatch 对象,将其计数器初始化为 1 :new CountDownLatch(1),多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。

如下例所示,在多线程运行的情况下,计算多线程耗费的时间:

  1. public class TestCountDownLatch {
  2. //CountDownLatch 为唯一的、共享的资源
  3. static CountDownLatch countDownLatch = new CountDownLatch(5);
  4. static class LatchDemo extends Thread{
  5. @Override
  6. public void run() {
  7. int sum = 0;
  8. for (int i = 0; i < 1000000; i++) {
  9. sum++;
  10. }
  11. System.out.println(getName()+"计算结果:"+sum);
  12. countDownLatch.countDown();
  13. }
  14. }
  15. public static void main(String[] args) throws InterruptedException {
  16. long begin = System.currentTimeMillis();
  17. System.out.println("开始了—–"+begin);
  18. for (int i = 0; i < 5; i++) {
  19. new LatchDemo().start();
  20. }
  21. countDownLatch.await();
  22. long end = System.currentTimeMillis();
  23. System.out.println("结束了—–"+end);
  24. System.out.println("总共用时:"+(endbegin));
  25. }
  26. }
  27. /**
  28. 开始了—–1571144894551
  29. Thread-3计算结果:1000000
  30. Thread-0计算结果:1000000
  31. Thread-1计算结果:1000000
  32. Thread-2计算结果:1000000
  33. Thread-4计算结果:1000000
  34. 结束了—–1571144894559
  35. 总共用时:8
  36. */

二、CyclicBarrier

【1】CyclicBarrier是什么?
​ CyclicBarrier即栅栏类,与CountDownLatch类似。它能阻塞一组线程直到某个事件的发生。栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。

​ CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。

【2】CyclicBarrier构造方法

  1. public CyclicBarrier(int parties) {
  2. this(parties, null);
  3. }
  4. public CyclicBarrier(int parties, Runnable barrierAction) {
  5. if (parties <= 0) throw new IllegalArgumentException();
  6. this.parties = parties;
  7. this.count = parties;
  8. this.barrierCommand = barrierAction;
  9. }

CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程使用await()方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

CyclicBarrier的另一个构造函数CyclicBarrier(int parties, Runnable barrierAction),用于线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。

【3】CyclicBarrier应用示例

  1. public class CyclicBarrierTest {
  2. // 自定义工作线程
  3. private static class Worker extends Thread {
  4. private CyclicBarrier cyclicBarrier;
  5. public Worker(CyclicBarrier cyclicBarrier) {
  6. this.cyclicBarrier = cyclicBarrier;
  7. }
  8. @Override
  9. public void run() {
  10. super.run();
  11. try {
  12. System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
  13. cyclicBarrier.await();
  14. System.out.println(Thread.currentThread().getName() + "开始执行");
  15. // 工作线程开始处理,这里用Thread.sleep()来模拟业务处理
  16. Thread.sleep(1000);
  17. System.out.println(Thread.currentThread().getName() + "执行完毕");
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  23. public static void main(String[] args) {
  24. int threadCount = 3;
  25. CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
  26. for (int i = 0; i < threadCount; i++) {
  27. System.out.println("创建工作线程" + i);
  28. Worker worker = new Worker(cyclicBarrier);
  29. worker.start();
  30. }
  31. }
  32. }
  33. /**
  34. 创建工作线程0
  35. 创建工作线程1
  36. Thread-0开始等待其他线程
  37. 创建工作线程2
  38. Thread-1开始等待其他线程
  39. Thread-2开始等待其他线程
  40. Thread-2开始执行
  41. Thread-0开始执行
  42. Thread-1开始执行
  43. Thread-1执行完毕
  44. Thread-0执行完毕
  45. Thread-2执行完毕
  46. */

在上述代码中,我们自定义的工作线程必须要等所有参与线程开始之后才可以执行,我们可以使用CyclicBarrier类来帮助我们完成。从程序的执行结果中也可以看出,所有的工作线程都运行await()方法之后都到达了栅栏位置,然后,3个工作线程才开始执行业务处理。

【4】CyclicBarrier和CountDownLatch的区别

  • CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,可以使用多次,所以CyclicBarrier能够处理更为复杂的场景;
  • CyclicBarrier还提供了一些其他有用的方法,比如getNumberWaiting()方法可以获得CyclicBarrier阻塞的线程数量,isBroken()方法用来了解阻塞的线程是否被中断;
  • CountDownLatch允许一个或多个线程等待一组事件的产生,而CyclicBarrier用于等待其他线程运行到栅栏位置。

三、Semaphore

【1】Semaphore是什么?
信号量(Semaphore),又被称为信号灯,在多线程环境下用于协调各个线程, 以保证它们能够正确、合理的使用公共资源。信号量维护了一个许可集,我们在初始化Semaphore时需要为这个许可集传入一个数量值,该数量值代表同一时间能访问共享资源的线程数量。

【2】Semaphore基本用法

线程可以通过acquire()方法获取到一个许可,然后对共享资源进行操作,注意如果许可集已分配完了,那么线程将进入等待状态,直到其他线程释放许可才有机会再获取许可,线程释放一个许可通过release()方法完成,"许可"将被归还给Semaphore。

【3】Semaphore实现互斥锁

  1. public class TestSemaphore {
  2. //初始化为1,互斥信号量
  3. private final static Semaphore mutex = new Semaphore(1);
  4. static class thread extends Thread{
  5. @Override
  6. public void run() {
  7. try {
  8. mutex.acquire();
  9. System.out.println(getName()+"开始工作");
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }finally {
  13. //使用完成释放锁
  14. mutex.release();
  15. System.out.println("锁释放!!!");
  16. }
  17. }
  18. }
  19. public static void main(String[] args) {
  20. for (int i = 0; i < 10; i++) {
  21. new Thread(new thread(),String.valueOf(i)).start();
  22. }
  23. }
  24. }

创建一个数量为1的互斥信号量Semaphore,然后并发执行10个线程,在线程中利用Semaphore控制线程的并发执行,因为信号量数值只有1,因此每次只能一条线程执行,其他线程进入等待状态。

四、Callable、Future和FutureTask

Java线程并发工具类CountDownLatch原理及用法

Future接口,一般都是取回Callable执行的状态用的。其中的主要方法:

  • cancel,取消Callable的执行,当Callable还没有完成时
  • get,获得Callable的返回值
  • isCanceled,判断是否取消了
  • isDone,判断是否完成

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

原文链接:https://www.cnblogs.com/lee0527/p/11686936.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Java线程并发工具类CountDownLatch原理及用法 https://www.kuaiidc.com/108335.html

相关文章

发表评论
暂无评论