countdownlatch.await所有的线程是一个集合吗

Java&5&开始引入的&Concurrent&并发软件包里面的&CountDownLatch&其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。&所以,CountDownLatch类可以用于控制多个线程同时开始运行,或者用于主线程等待所有子线程都结束。举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:&
1 public class Worker implements Runnable{
private CountDownLatch downL
public Worker(CountDownLatch downLatch, String name){
this.downLatch = downL
this.name =
public void run() {
this.doWork();
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
}catch(InterruptedException ie){
System.out.println(this.name + "活干完了!");
this.downLatch.countDown();
private void doWork()
System.out.println(this.name + "正在干活!");
30 ==================
32 public class Boss implements Runnable {
private CountDownLatch downL
public Boss(CountDownLatch downLatch){
this.downLatch = downL
public void run() {
System.out.println("老板正在等所有的工人干完活......");
this.downLatch.await();
} catch (InterruptedException e) {
System.out.println("工人活都干完了,老板开始检查了!");
52 ============================
54 public class CountDownLatchDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(3);
Worker w1 = new Worker(latch,"张三");
Worker w2 = new Worker(latch,"李四");
Worker w3 = new Worker(latch,"王二");
Boss boss = new Boss(latch);
executor.execute(w3);
executor.execute(w2);
executor.execute(w1);
executor.execute(boss);
executor.shutdown();
阅读(...) 评论()多线程执行顺序控制? - 知乎85被浏览5316分享邀请回答611 条评论分享收藏感谢收起package main
"sync/atomic"
func main() {
papers := [][]int{
{1, 3, 5, 7, 9},
{2, 4, 6, 8, 10},
{1, 1, 2, 3, 5, 8},
{2, 3, 5, 7, 11, 13, 17},
var done []chan struct{}
for range papers {
done = append(done, make(chan struct{}))
// 用于计算的线程数
nThreads := 8
sem := make(chan struct{}, nThreads)
for iPaper, tests := range papers {
var nTests int64 = int64(len(tests))
var nChecked int64
iPaper := iPaper
for _, test := range tests {
test := test
sem &- struct{}{}
go func() {
defer func() {
// 计算,简化成直接返回一个数字
points := test
go func() {
// 等待前面的试卷完成
for i := 0; i & iPaper; i++ {
fmt.Printf("%d ", points)
// 最后一题,则标记完成该试卷
if n := atomic.AddInt64(&nChecked, 1); n == nTests {
fmt.Printf("\n")
close(done[iPaper])
// 等待最后一份完成
&-done[len(done)-1]
几次输出& ./a
10 8 4 6 2
1 1 3 2 5 8
5 3 2 13 11 7 17
10 8 6 4 2
1 1 8 5 2 3
3 2 17 13 11 7 5
6 10 2 8 4
8 1 2 3 1 5
2 11 3 7 17 13 5
2 4 6 8 10
1 1 2 3 5 8
17 2 3 5 7 11 13
2 4 8 6 10
5 2 3 8 1 1
17 13 11 2 7 3 5
8 10 6 2 4
8 1 1 2 3 5
7 17 13 5 2 3 11
8 6 4 10 2
1 1 2 3 5 8
17 13 7 5 2 3 11
符合题目要求=== update ===另一个实现,动态创建线程可能java实现起来不经济,下面是用固定线程的原理是每次计算完,都尽量输出,不能输出就存起来可以另起一个线程做检查,计算线程把结果传过去,这样可以不用那个锁package main
"encoding/binary"
"math/rand"
crand "crypto/rand"
func main() {
papers := [][]int{
{1, 3, 5, 7, 9},
{2, 4, 6, 8, 10},
{1, 1, 2, 3, 5, 8},
{2, 3, 5, 7, 11, 13, 17},
waitGroup := new(sync.WaitGroup)
numTests := make([]int64, len(papers))
for i, tests := range papers {
numTests[i] = int64(len(tests))
waitGroup.Add(len(tests))
type Job struct {
jobs := make(chan Job)
// 越大,允许缓存的结果越多。为1时,顺序计算所有题目
sem := make(chan struct{}, 1)
go func() {
for iPaper, tests := range papers {
for i, test := range tests {
sem &- struct{}{}
jobs &- Job{
Paper: iPaper,
Input: test,
type Result int
currentPaper := 0
results := make([][]Result, len(papers))
lock := new(sync.Mutex)
nThread := 8
for i := 0; i & nThread; i++ {
go func() {
for job := range jobs {
result := func() Result {
// 随机sleep模拟计算抖动
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
return Result(job.Input)
lock.Lock()
if job.Paper == currentPaper { // 可以输出
fmt.Printf("%d ", result)
numTests[job.Paper]--
if numTests[job.Paper] == 0 { // 当前试卷已全部输出
fmt.Printf("\n")
stepPaper:
currentPaper++ // 下一张
if currentPaper & len(papers) {
for _, result := range results[currentPaper] { // 输出保存的结果
fmt.Printf("%d ", result)
numTests[currentPaper] -= int64(len(results[currentPaper]))
results[currentPaper] = make([]Result, 0)
if numTests[currentPaper] == 0 { // 如果该页也全部输出了,继续下一页
fmt.Printf("\n")
goto stepPaper
} else { // 未能输出,保存
results[job.Paper] = append(results[job.Paper], result)
lock.Unlock()
waitGroup.Done()
waitGroup.Wait()
close(jobs)
func init() {
var seed int64
binary.Read(crand.Reader, binary.LittleEndian, &seed)
rand.Seed(seed)
714 条评论分享收藏感谢收起更多与世界分享知识、经验和见解使用CountDownLatch优化一个耗时的请求 - 开源中国社区
当前访客身份:游客 [
当前位置:
发布于 日 17时,
因为是跨部门合作,需要把对方传递的集合对象解析成自己的集合对象,并且这个方法是用来提供给servlet调用,对响应时间的要求高于服务器压力的要求。&使用原始的for循环调用耗时在5秒左右,使用CountDownLatch+runnable线程后,在2、3秒之间,使用CountDownLatch+runnable线程+线程池后,响应时间在1、2秒之间。
代码片段(1)
1.&[代码]parseFeedData:原始的循环执行,parseFeedDataAsync:异步线程池执行&&&&
* @category 解析动态列表-for循环
* @param userid
* @param list
* @return List&BroadcastData&
public static List&BroadcastData& parseFeedData(int userid, List&FeedData& list) {
List&BroadcastData& result = new ArrayList&BroadcastData&();
if (null != list) {
for (FeedData fdata : list) {
BroadcastData bdata = parseFeedData(userid, fdata);
if ((null != bdata && !bdata.content.isEmpty()) || (null != bdata.images && !bdata.images.isEmpty())
|| (null != bdata.videos && !bdata.videos.isEmpty())) {
result.add(bdata);
} catch (Exception e) {
logger.error("BroadcastHelper parseFeedData accurred an error:" + e);
* @category 解析动态列表-CountDownLatch异步
* @param userid
* @param list
* @return List&BroadcastData&
* @throws ServerTimeoutException
public static List&BroadcastData& parseFeedDataAsync(final int userid, List&FeedData& list) throws ServerTimeoutException {
("parseFeedDataAsync called.");
StopWatch watch = new StopWatch();
watch.reset();
watch.start();
if (null != list) {
final CountDownLatch latch = new CountDownLatch(list.size());
final List&BroadcastData& data = Collections.synchronizedList(new ArrayList&BroadcastData&(list.size()));
final ExecutorService threadPool = Executors.newFixedThreadPool(10);// 可指定list.size(),是否有必要,待验证
for (final FeedData fdata : list) {
Runnable task = new Runnable() {
public void run() {
("parseFeedDataAsync sub thread run.");
BroadcastD
bdata = parseFeedData(userid, fdata);
if ((null != bdata && !bdata.content.isEmpty()) || (null != bdata.images && !bdata.images.isEmpty())
|| (null != bdata.videos && !bdata.videos.isEmpty())) {
data.add(bdata);
} catch (Exception e) {
logger.error("parseFeedDataAsync sub thread run error:" + e);
} finally {
latch.countDown();
// task.run();//用原始的线程跑,比用线程池要慢一倍
threadPool.submit(task);
} catch (Exception e) {
logger.error("parseFeedDataAsync occurred an error:" + e);
boolean bSuccess =
while (true) {
bSuccess = latch.await(120L, TimeUnit.SECONDS);
threadPool.shutdown();
} catch (InterruptedException e) {
logger.error("parseFeedDataAsync CountDownLatch await InterruptedException.");
if (!bSuccess)
throw new ServerTimeoutException("parseFeedDataAsync CountDownLatch timeout");
Collections.sort(data, new Comparator&BroadcastData&() {
public int compare(BroadcastData o1, BroadcastData o2) {
return o1.getBroadid() & o2.getBroadid() ? 1 : 0;
watch.stop();
(String.format("[# parseFeedDataAsync=& consume=%s/ms #]", watch.getTime()));
开源中国-程序员在线工具:
相关的代码(218)
2楼:心意星逸 发表于
task.run()并不会启动线程,task.start()才会启动线程。所以如果是调用task.run(),那还是在一个线程执行的。
3楼:优雅先生 发表于
&o1.getBroadid() & o2.getBroadid() ?&1
&:&0;这个是否改成
&o1.getBroadid() - o2.getBroadid() ;更妥当点呢?
4楼:liango 发表于
开源从代码分享开始
codeskills的其它代码CountDownLatch的介绍和使用 - countdownlatch - ITkeyowrd
CountDownLatch的介绍和使用
推荐:申明:个人学习总计,仅供参考,欢迎批评指正与交流。 public class Main {
private static final int COUNT = 100;
private static int poolSize = -1
1、类介绍java.util.concurrent类 CountDownLatchjava.lang.Objectjava.util.concurrent.CountDownLatch一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次――计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。2、使用场景在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作。 这个时候就可以使用CountDownLatch。CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了。3、方法说明countDownpublic void countDown()递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少。如果新的计数为零,出于线程调度目的,将重新启用所有的等待线程。如果当前计数等于零,则不发生任何操作。awaitpublic boolean await(long timeout,TimeUnit unit)throws InterruptedException使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true 值。如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直处于休眠状态:如果计数到达零,则该方法返回 true 值。如果当前线程:则抛出 InterruptedException,并且清除当前线程的已中断状态。如果超出了指定的等待时间,则返回值为 false。如果该时间小于等于零,则此方法根本不会等待。 在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,由于调用 countDown() 方法,计数到达零;或者其他某个线程中断当前线程;或者已超出指定的等待时间。参数:timeout - 要等待的最长时间unit - timeout 参数的时间单位。返回:如果计数到达零,则返回 true;如果在计数到达零之前超过了等待时间,则返回 false抛出:InterruptedException - 如果当前线程在等待时被中断4、相关实例// 一个CountDouwnLatch实例是不能重复使用的,也就是说它是一次性的,锁一经被打开就不能再关闭使用了,如果想重复使用,请考虑使用CyclicBarrier。public class CountDownLatchTest {// 模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。public static vo推荐:本文将介绍CountDownLatch工具类,并采用这个工具类给出一个实例。1. CountDownLatch工具类介绍CountDownLatch是一个同步工具类,它允许一个或多个线程处于id main(String[] args) throws InterruptedException {// 开始的倒数锁final CountDownLatch begin = new CountDownLatch(1);// 结束的倒数锁final CountDownLatch end = new CountDownLatch(10);// 十名选手final ExecutorService exec = Executors.newFixedThreadPool(10);for (int index = 0; index & 10; index++) {final int NO = index + 1;Runnable run = new Runnable() {public void run() {try {// 如果当前计数为零,则此方法立即返回。// 等待begin.await();Thread.sleep((long) (Math.random() * 10000));System.out.println(&No.& + NO + & arrived&);} catch (InterruptedException e) {} finally {// 每个选手到达终点时,end就减一end.countDown();}}};exec.submit(run);}System.out.println(&Game Start&);// begin减一,开始游戏begin.countDown();// 等待end变为0,即所有选手到达终点end.await();System.out.println(&Game Over&);exec.shutdown();}}原文链接:/the-introduction-and-use-of-a-countdownlatch.html
推荐:java并发编程中CountDownLatch和CyclicBarrier的使用
在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决?
1、类介绍java.util.concurrent类 CountDownLatchjava.lang.Objectjava.util.concurrent.CountDownLatch一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等
相关阅读排行
相关内容推荐
请激活账号
为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。
您的注册邮箱:
如果您没有收到激活邮件,请注意检查垃圾箱。问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
比如StringBuilder在多线程中使用会导致线程不安全,这个不安全会产生什么后果,是数据不正确或丢失.?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
我先给上一段代码,你可以自己运行一下试一试:
public class Main {
public static void main(String[] args) {
// 用来测试的ArrayList
List&Object& list = new ArrayList&Object&();
// 线程数量(1000)
int threadCount = 1000;
// 用来让主线程等待threadCount个子线程执行完毕
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
// 启动threadCount个子线程
for (int i = 0; i & threadC i++) {
Thread thread = new Thread(new MyThread(list, countDownLatch));
thread.start();
// 主线程等待所有子线程执行完成,再向下执行
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
// List的size
System.out.println(list.size());
class MyThread implements Runnable {
private List&Object&
private CountDownLatch countDownL
public MyThread(List&Object& list, CountDownLatch countDownLatch) {
this.list =
this.countDownLatch = countDownL
public void run() {
// 每个线程向List中添加100个元素
for (int i = 0; i & 100; i++) {
list.add(new Object());
// 完成一个子线程
countDownLatch.countDown();
上面的代码中,在主线程中new了一个非线程安全的ArrayList,然后开1000个线程分别向这个ArrayList里面添加元素,每个线程添加100个元素,等所有线程执行完成后,这个ArrayList的size应该是多少?应该是100000个?
然而实际运行结果可能不是100000!结果可能会是9...这就是非线程安全的集合在多线程操作的情况下导致不正确的结果。
具体线程安全这块可以参考我写的一篇博客:
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 App

我要回帖

更多关于 latch.countdown 的文章

 

随机推荐