Java并发新构件之CounDownLatch

简介:

    CountDownLatch主要用于同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成。

    你可以向CountDownLatch对象设置一个初始计数值,任何在这个对象上调用wait()的方法都将阻塞,直到这个计数值达到0.其他任务在结束其工作时,可以在该对象上调用countDown()来减小这个计数值,你可以通过调用getCount()方法来获取当前的计数值。CountDownLatch被设计为只触发一次,计数值不能被重置。如果你需要能够重置计数值的版本,则可以使用CyclicBarrier。

    调用countDown()的任务在产生这个调用时并没有阻塞,只有对await()的调用会被阻塞,直到计数值到达0。

    CountDownLatch的典型用法是将一个程序分为n个互相独立的可解决人物,并创建值为0的CountDownLatch。当每个任务完成是,都会在这个锁存器上调用countDown()。等待问题被解决的任务在这个锁存器上调用await(),将它们自己锁住,直到锁存器计数结束。下面是演示这种技术的一个框架示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import  java.util.Random;
import  java.util.concurrent.CountDownLatch;
import  java.util.concurrent.DelayQueue;
import  java.util.concurrent.ExecutorService;
import  java.util.concurrent.Executors;
import  java.util.concurrent.TimeUnit;
 
class  TaskPortion  implements  Runnable {
     private  static  int  counter =  0 ;
     private  final  int  id = counter++;
     private  static  Random random =  new  Random();
     private  final  CountDownLatch latch;
     public  TaskPortion(CountDownLatch latch) {
         this .latch = latch;
     }
     @Override
     public  void  run() {
         try  {
             doWork();
             latch.countDown(); //普通任务执行完后,调用countDown()方法,减少count的值
             System.out.println( this  " completed. count="  + latch.getCount());
         catch  (InterruptedException e) {
             
         }
     }
     
     public  void  doWork()  throws  InterruptedException {
         TimeUnit.MILLISECONDS.sleep(random.nextInt( 2000 ));
     }
     
     @Override
     public  String toString() {
         return  String.format( "%1$-2d " , id);
     }
}
 
class  WaitingTask  implements  Runnable {
     private  static  int  counter =  0 ;
     private  final  int  id = counter++;
     private  final  CountDownLatch latch;
     public  WaitingTask(CountDownLatch latch) {
         this .latch = latch;
     }
     @Override
     public  void  run() {
         try  {
             //这些后续任务需要等到之前的任务都执行完成后才能执行,即count=0时
             latch.await();
             System.out.println( "Latch barrier passed for "  this );
         catch  (InterruptedException e) {
             System.out.println( this  " interrupted." );
         }
     }
     
     @Override
     public  String toString() {
         return  String.format( "WaitingTask %1$-2d " , id);
     }
}
 
public  class  CountDownLatchDemo {
     static  final  int  SIZE =  10 ;
     public  static  void  main(String[] args) {
         CountDownLatch latch =  new  CountDownLatch(SIZE);
         ExecutorService exec = Executors.newCachedThreadPool();
         //10个WaitingTask
         for  ( int  i =  0 ; i <  5 ; i++) {
             exec.execute( new  WaitingTask(latch));
         }
         //100个任务,这100个任务要先执行才会执行WaitingTask
         for  ( int  i =  0 ; i < SIZE; i++) {
             exec.execute( new  TaskPortion(latch));
         }
         System.out.println( "Launched all tasks." );
         exec.shutdown(); //当所有的任务都结束时,关闭exec
     }
}

执行结果(可能的结果):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Launched all tasks.
4    completed. count= 9
6    completed. count= 8
3    completed. count= 7
0    completed. count= 6
2    completed. count= 5
1    completed. count= 4
5    completed. count= 3
7    completed. count= 2
9    completed. count= 1
8    completed. count= 0
Latch barrier passed  for  WaitingTask  0  
Latch barrier passed  for  WaitingTask  2  
Latch barrier passed  for  WaitingTask  1  
Latch barrier passed  for  WaitingTask  3  
Latch barrier passed  for  WaitingTask  4

    从结果中可以看到,所有的WaitingTask都是在所有的TaskPortion执行完成之后执行的。

    TaskPortion将随机的休眠一段时间,以模拟这部分工作的完成。而WaitingTask表示系统中必须等待的部分,它要等到问题的初始部分完成后才能执行。注意:所有任务都使用了在main()中定义的同一个CountDownLatch对象。

目录
相关文章
|
1月前
|
存储 安全 算法
解读 Java 并发队列 BlockingQueue
解读 Java 并发队列 BlockingQueue
20 0
|
1天前
|
Java API 调度
[Java并发基础]多进程编程
[Java并发基础]多进程编程
|
6天前
|
安全 Java
深入理解 Java 多线程和并发工具类
【4月更文挑战第19天】本文探讨了Java多线程和并发工具类在实现高性能应用程序中的关键作用。通过继承`Thread`或实现`Runnable`创建线程,利用`Executors`管理线程池,以及使用`Semaphore`、`CountDownLatch`和`CyclicBarrier`进行线程同步。保证线程安全、实现线程协作和性能调优(如设置线程池大小、避免不必要同步)是重要环节。理解并恰当运用这些工具能提升程序效率和可靠性。
|
8天前
|
Java 开发者
Java中多线程并发控制的实现与优化
【4月更文挑战第17天】 在现代软件开发中,多线程编程已成为提升应用性能和响应能力的关键手段。特别是在Java语言中,由于其平台无关性和强大的运行时环境,多线程技术的应用尤为广泛。本文将深入探讨Java多线程的并发控制机制,包括基本的同步方法、死锁问题以及高级并发工具如java.util.concurrent包的使用。通过分析多线程环境下的竞态条件、资源争夺和线程协调问题,我们提出了一系列实现和优化策略,旨在帮助开发者构建更加健壮、高效的多线程应用。
7 0
|
8天前
|
存储 缓存 安全
Java并发基础之互斥同步、非阻塞同步、指令重排与volatile
在Java中,多线程编程常常涉及到共享数据的访问,这时候就需要考虑线程安全问题。Java提供了多种机制来实现线程安全,其中包括互斥同步(Mutex Synchronization)、非阻塞同步(Non-blocking Synchronization)、以及volatile关键字等。 互斥同步(Mutex Synchronization) 互斥同步是一种基本的同步手段,它要求在任何时刻,只有一个线程可以执行某个方法或某个代码块,其他线程必须等待。Java中的synchronized关键字就是实现互斥同步的常用手段。当一个线程进入一个synchronized方法或代码块时,它需要先获得锁,如果
24 0
|
17天前
|
存储 缓存 安全
【企业级理解】高效并发之Java内存模型
【企业级理解】高效并发之Java内存模型
|
24天前
|
安全 Java
Java中的多线程并发控制
在Java中,多线程是实现并发执行任务的一种重要方式。然而,随着多个线程同时访问共享资源,可能会导致数据不一致和其他并发问题。因此,了解并掌握Java中的多线程并发控制机制显得尤为重要。本文将深入探讨Java的多线程并发控制,包括synchronized关键字、Lock接口、Semaphore类以及CountDownLatch类等,并通过实例代码演示其使用方法和注意事项。
12 2
|
28天前
|
缓存 NoSQL Java
Java项目:支持并发的秒杀项目(基于Redis)
Java项目:支持并发的秒杀项目(基于Redis)
26 0
|
30天前
|
算法 安全 Java
Java中的并发编程:理解并发性能优化
在当今软件开发领域,多核处理器的普及使得并发编程变得更加重要。本文将深入探讨Java中的并发编程,介绍并发性能优化的关键技术,帮助开发人员更好地利用多核处理器提升应用程序性能。
|
1月前
|
安全 Java API
Java并发 - J.U.C并发容器类 list、set、queue
Queue API 阻塞是通过 condition 来实现的,可参考 Java 并发 - Lock 接口 ArrayBlockingQueue 阻塞 LinkedBlockingQueue 阻塞 ArrayQueue 非阻塞 LinkedQueue 非阻塞