Java并发编程:CountDownLatch的使用以及一个容易踩到的陷阱


声明:本文转载自https://my.oschina.net/u/2338224/blog/1612549,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

使用简介

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(); 			} 		} 	} } 

运行结果:

 

本文发表于2018年01月24日 20:32
(c)注:本文转载自https://my.oschina.net/u/2338224/blog/1612549,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2182 讨论 0 喜欢 1

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1