Java并发编程:CountDownLatch的使用以及一个容易踩到的陷阱
2018-01-24 19:56
609 查看
摘要: Java并发编程:CountDownLatch
CountDownLatch所描述的是”在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待“。在API中是这样描述的:
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
运行这段程序发现经常程序无法结束,死等在原地, 原因就出现在main里面的for循环那一行,countDownLatch.getCount()是个会变的东西, 用来放在for循环里面,会影响循环计数,这是个很隐秘的陷阱!
使用简介
CountDownLatch是通过一个计数器来实现的,当我们在new 一个CountDownLatch对象的时候需要带入该计数器值,该值就表示了线程的数量。每当一个线程完成自己的任务后,计数器的值就会减1。当计数器的值变为0时,就表示所有的线程均已经完成了任务,然后就可以恢复等待的线程继续执行了。CountDownLatch所描述的是”在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待“。在API中是这样描述的:
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
应用示例
示例使用开会案例。老板进入会议室等待5个人全部到达会议室才会开会。所以这里有两个线程老板等待开会线程、员工到达会议室,下面这段程序有惊天陷阱,请勿copy!:陷阱程序:
package com.chenjun.testxxx; import java.util.concurrent.CountDownLatch; public class CountDownLatchTest { private static CountDownLatch countDownLatch = new CountDownLatch(5); static class BossThread extends Thread { @Override public void run() { System.out.println("Boss在会议室等待,总共有" + countDownLatch.getCount() + "个人开会..."); try { // Boss等待 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("所有人都已经到齐了,开会吧..."); } // 员工到达会议室 static class EmpleoyeeThread extends Thread { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + ",到达会议室...."); }finally { // 员工到达会议室 count - 1 countDownLatch.countDown(); } } } public static void main(String[] args) { // Boss线程启动 new BossThread().start(); for (long i = 0; i < countDownLatch.getCount(); i++) { new EmpleoyeeThread().start(); } } } }
运行这段程序发现经常程序无法结束,死等在原地, 原因就出现在main里面的for循环那一行,countDownLatch.getCount()是个会变的东西, 用来放在for循环里面,会影响循环计数,这是个很隐秘的陷阱!
改造后的程序:
package com.chenjun.testxxx; import java.util.concurrent.CountDownLatch; public class CountDownLatchTest { private static CountDownLatch countDownLatch = new CountDownLatch(5); static class BossThread extends Thread { @Override public void run() { System.out.println("Boss在会议室等待,总共有" + countDownLatch.getCount() + "个人开会..."); try { // Boss等待 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("所有人都已经到齐了,开会吧..."); } // 员工到达会议室 static class EmpleoyeeThread extends Thread { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + ",到达会议室...."); }finally { // 员工到达会议室 count - 1 countDownLatch.countDown(); } } } public static void main(String[] args) { // Boss线程启动 new BossThread().start(); long cnt = countDownLatch.getCount(); for (long i = 0; i < cnt; i++) { new EmpleoyeeThread().start(); } } } }
运行结果:
相关文章推荐
- Java并发编程之2——同步工具类的使用(CountDownLatch,CyclicBarrier,BlockungQueue,Semaphore)
- 使用Java辅助类(CountDownLatch、CyclicBarrier、Semaphore)并发编程
- Java 并发编程实战学习笔记——CountDownLatch的使用
- java并发编程之CountDownLatch
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程之CountDownLatch
- java并发编程---如何创建线程以及Thread类的使用
- Java并发基础(五)-CountDownLatch、CyclocBarrier、Phaser的使用
- JAVA并发编程-障碍器CyclicBarrier,计数器CountDownLatch,信号量Semaphore
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- 《Java 7 并发编程指南》学习概要 (3)Semaphore, CountDownLatch, CyclicBarrier , Phaser, Exchanger
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- java并发编程之CountDownLatch
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Android AsyncTask完全解析FutureTask 深度解析 -Java并发编程:Callable、Future和FutureTask一个使用DownloadManager下载文件的小例
- Java多线程编程之CountDownLatch同步工具使用实例
- JAVA并发编程--Semaphore、CountDownLatch、ReentrantLock、CyclicBarrier
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程-同步辅助类之CountDownLatch
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore