摘要:当计数器值到达时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。这个类使用线程在达到某个条件后继续执行的情况。
CountDownLatch
CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
调用CountDownLatch类的await()方法会一直阻塞,直到其他线程调用CountDown()方法使计数器的值减1,当计数器的值等于0则当因调用await()方法处于阻塞状态的线程会被唤醒继续执行。计数器是不能被重置的。这个类使用线程在达到某个条件后继续执行的情况。比如并行计算,计算量特别大,我可以将计算量拆分成多个线程进行计算,最后将结果汇总。
一个CountdownLatch 例子
@Slf4j public class CountDownLatchExample1 { private final static int threadCount = 200; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { test(threadNum); } catch (Exception e) { log.error("exception", e); } finally { countDownLatch.countDown(); } }); } countDownLatch.await(); log.info("finish"); exec.shutdown(); } private static void test(int threadNum) throws Exception { Thread.sleep(100); log.info("{}", threadNum); Thread.sleep(100); } }
我们在线程之后都调用了countDown方法,在执行log之前调用了await方法,从而来保证打印日志时一定是在所有线程执行完。假设我们不使用CountDownLatch时结果会怎么样?
@Slf4j public class CountDownLatchExample1 { private final static int threadCount = 200; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { test(threadNum); } catch (Exception e) { log.error("exception", e); } // finally { //// countDownLatch.countDown(); // } }); } // countDownLatch.await(); log.info("finish"); // exec.shutdown(); } private static void test(int threadNum) throws Exception { Thread.sleep(100); log.info("{}", threadNum); Thread.sleep(100); } }
这段代码打印结果就是,一开始就打印出了finish,因为这个打印是在主线程中执行。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/77633.html
摘要:在创建对象时,需要转入一个值,用于初始化的成员变量,该成员变量表示屏障拦截的线程数。当到达屏障的线程数小于时,这些线程都会被阻塞住。当所有线程到达屏障后,将会被更新,表示进入新一轮的运行轮次中。 1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个...
摘要:也是一个同步辅助类,它允许一组线程相互等待直到到达某个工作屏障点,通过他可以完成多线程之间的相互等待。每个线程都就绪之后才能执行后面的操作。是可重用的计数器,的使用场景和的使用场景很相似,可以用于多线程计算数据最后总计结果。 CyclicBarrier CyclicBarrier也是一个同步辅助类,它允许一组线程相互等待直到到达某个工作屏障点,通过他可以完成多线程之间的相互等待。每个线...
摘要:性能较好是因为避免了线程进入内核的阻塞状态请求总数同时并发执行的线程数我们首先使用声明一个所得实例,然后使用进行加锁和解锁操作。 ReentrantLock与锁 Synchronized和ReentrantLock异同 可重入性:两者都具有可重入性 锁的实现:Synchronized是依赖jvm实现的,ReentrantLock是jdk实现的。(我们可以理解为一个是操作系统层面的实现...
摘要:好了,继续向下执行,尝试获取锁失败后,会调用首先通过方法,将包装成共享结点,插入等待队列,插入完成后队列结构如下然后会进入自旋操作,先尝试获取一次锁,显然此时是获取失败的主线程还未调用,同步状态还是。 showImg(https://segmentfault.com/img/remote/1460000016012541); 本文首发于一世流云的专栏:https://segmentfa...
摘要:在多线程编程中我们会遇到很多需要使用线程同步机制去解决的并发问题,而这些同步机制就是多线程编程中影响正确性和运行效率的重中之重。这五个方法之所以能指定同步器的行为,则是因为中的其他方法就是通过对这五个方法的调用来实现的。 在多线程编程中我们会遇到很多需要使用线程同步机制去解决的并发问题,而这些同步机制就是多线程编程中影响正确性和运行效率的重中之重。这不禁让我感到好奇,这些同步机制是如何...
阅读 2421·2021-10-11 10:57
阅读 1276·2021-10-09 09:59
阅读 1988·2019-08-30 15:53
阅读 3207·2019-08-30 15:53
阅读 1004·2019-08-30 15:45
阅读 729·2019-08-30 15:44
阅读 3436·2019-08-30 14:24
阅读 947·2019-08-30 14:21