并发编程常用工具类之countDownLatch和cyclicBarrier的使用对比

1.CountDownLatch

          countDownLatch的作用是让一组线程等待其他线程完成工作以后在执行,相当于加强版的join(不懂可以百度一下join的用法),一般在初始化的时候会在构造方法传入计数器,

后续,在其他线程中每次调用countDown方法计数器减一,一般在需要等待的线程中调用countDownLatch的await方法阻塞线程,在当计数器为0时,等待线程继续运行。

光看上面的定义描述不是很直观,我们再来结合代码看一下实际运用:

 1 public class UseCountDownLatch {
 2
 3     static CountDownLatch latch = new CountDownLatch(6);
 4     //初始化线程(只有一步,有4个)
 5     private static class InitThread implements Runnable{
 6
 7         @Override
 8         public void run() {
 9             System.out.println("Thread_"+Thread.currentThread().getId()
10                     +" ready init work......");
11             latch.countDown();//初始化线程完成工作了,countDown方法只扣减一次;
12             for(int i =0;i<2;i++) {
13                 System.out.println("Thread_"+Thread.currentThread().getId()
14                         +" ........continue do its work");
15             }
16         }
17     }
18     //业务线程
19     private static class BusiThread implements Runnable{
20
21         @Override
22         public void run() {
23             try {
24                 latch.await();
25             } catch (InterruptedException e) {
26                 e.printStackTrace();
27             }
28             for(int i =0;i<3;i++) {
29                 System.out.println("BusiThread_"+Thread.currentThread().getId()
30                         +" do business-----");
31             }
32         }
33     }
34
35     public static void main(String[] args) throws InterruptedException {
36         //单独的初始化线程,初始化分为2步,需要扣减两次
37         new Thread(new Runnable() {
38             @Override
39             public void run() {
40                 SleepTools.ms(1);
41                 System.out.println("Thread_"+Thread.currentThread().getId()
42                         +" ready init work step 1st......");
43                 latch.countDown();//每完成一步初始化工作,扣减一次
44                 System.out.println("begin step 2nd.......");
45                 SleepTools.ms(1);
46                 System.out.println("Thread_"+Thread.currentThread().getId()
47                         +" ready init work step 2nd......");
48                 latch.countDown();//每完成一步初始化工作,扣减一次
49             }
50         }).start();
51         new Thread(new BusiThread()).start();
52         for(int i=0;i<=3;i++){
53             Thread thread = new Thread(new InitThread());
54             thread.start();
55         }
56
57         latch.await();
58         System.out.println("Main do ites work........");
59     }
60 }

运行结果可以看到,两个初始化线程先跑,当两个初始化线程跑完了,latch的计数器减为0,阻塞放开,主线程和业务线程继续往下运行。但是,在设计这部分算法的时候需要注意,有可能会出现计数器没有减为0,则线程一直阻塞,导致程序卡死。

countDownLatch一般使用在多线程并发之后需要对结果进行处理,而我们无法控制所有线程的执行时间,所以在这里加上阻塞,等到只有线程全部执行完。

2.CyclicBarrier

          cyclicBarrier从业务角度来说,和countDownLatch比较类似(具体对比后面会专门介绍),其作用类似一个屏障(英文中也是屏障的意思),阻隔线程直到全部到达屏障点,放开屏障。一般可以用在多线程统计的时候,

从代码角度来看,cyclicBarrier有两个构造方法,CyclicBarrier(int parties)和CyclicBarrier(int parties, Runnable barrierAction);

两个方法的区别是第一个只是记录了线程计数器的个数,而第二个不仅记录了计数器,当屏障放开时,会执行第二个参数线程的方法(第二个参数一般传入的是一个实现了Runnable的线程方法)

再来结合代码深入了解一下:

 1 public class UseCyclicBarrier {
 2
 3     private static CyclicBarrier barrier
 4         = new CyclicBarrier(5,new CollectThread());
 5
 6     private static ConcurrentHashMap<String,Long> resultMap
 7             = new ConcurrentHashMap<>();//存放子线程工作结果的容器
 8
 9     public static void main(String[] args) {
10         new Thread(){
11             @Override
12             public void run() {
13                 long id = Thread.currentThread().getId();//线程本身的处理结果
14                 resultMap.put(Thread.currentThread().getId()+"",id);
15                 Random r = new Random();//随机决定工作线程的是否睡眠
16                 try {
17                     if(r.nextBoolean()) {
18                         Thread.sleep(2000+id);
19                         System.out.println("Thread_"+id+" ....do something ");
20                     }
21                     System.out.println(id+"....is await");
22                     barrier.await();
23                     Thread.sleep(1000+id);
24                     System.out.println("Thread_"+id+" ....do its business ");
25                 } catch (Exception e) {
26                     e.printStackTrace();
27                 }
28             }
29         }.start();
30         for(int i=0;i<=3;i++){
31             Thread thread = new Thread(new SubThread());
32             thread.start();
33         }
34     }
35
36     //负责屏障开放以后的工作
37     private static class CollectThread implements Runnable{
38
39         @Override
40         public void run() {
41             StringBuilder result = new StringBuilder();
42             for(Map.Entry<String,Long> workResult:resultMap.entrySet()){
43                 result.append("["+workResult.getValue()+"]");
44             }
45             System.out.println(" the result = "+ result);
46             System.out.println("do other business........");
47         }
48     }
49
50     //工作线程
51     private static class SubThread implements Runnable{
52
53         @Override
54         public void run() {
55             long id = Thread.currentThread().getId();//线程本身的处理结果
56             resultMap.put(Thread.currentThread().getId()+"",id);
57             Random r = new Random();//随机决定工作线程的是否睡眠
58             try {
59                 if(r.nextBoolean()) {
60                     Thread.sleep(2000+id);
61                     System.out.println("Thread_"+id+" ....do something ");
62                 }
63                 System.out.println(id+"....is await");
64                 barrier.await();
65                 Thread.sleep(1000+id);
66                 System.out.println("Thread_"+id+" ....do its business ");
67             } catch (Exception e) {
68                 e.printStackTrace();
69             }
70         }
71     }
72 }

输出结果:       11....is await
                            12....is await
                             Thread_10 ....do something
                     10....is await
Thread_13 ....do something
13....is await
Thread_14 ....do something
14....is await
 the result = [11][12][13][14][10]
do other business........
Thread_10 ....do its business
Thread_11 ....do its business
Thread_12 ....do its business
Thread_13 ....do its business
Thread_14 ....do its business

3.countDownLatch和cyclicBarrier区别

        (1)countDownlatch的计数器由调用countDown方法次数决定,每次调用计数器减一,可以在一个线程中调用多次,而cyclicBarrier计数器取决调用await方法的线程个数。

(2)  countDownLatch只能用一次,而cyclicBarrier可以循环使用。并且cyclicBarrier可以调用reset方法重置计数器,可以在线程故障重新启用线程调用。

(3)  二者在内部方法也有很多区别,具体有兴趣的可以去看看源码。

          

原文地址:https://www.cnblogs.com/gmt-hao/p/9476063.html

时间: 2025-01-04 20:40:37

并发编程常用工具类之countDownLatch和cyclicBarrier的使用对比的相关文章

并发编程常用工具类(二) SymaPhore实现线程池

1.symaPhore简介 symaphore(信号量)用来控制同时访问某个资源的线程数量,一般用在并发流量控制.个人对它的理解相当于是接待室每次只能接待固定数量的人,当达到最高接待数的时候,其他人就会被拦截在外等待,当前面接待完走出接待室,才会继续接待下面的人. 2.symaphore使用 symaphore有两个构造方法:构造方法Semaphore(int permits)接受一个int参数,表示可用的许可证数量,内部默认创建一个非公平锁:构造方法Semaphore(int permits,

并发工具类:CountDownLatch、CyclicBarrier、Semaphore

在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch 1 import java.util.concurrent.CountDownLatch; 2 3 4 public class CountDownLatchTest 5 { //设置N为2 6 static CountDownLatch c = new CountDownLatch(2); 7 p

【转】Java并发编程:Thread类的使用

Java并发编程:Thread类的使用 Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知识:线程的几种状态.上下文切换,然后接着介绍Thread类中的方法的具体使用. 以下是本文的目录大纲: 一.线程的状态 二.上下文切换 三.Thread类中的方法 若有不正之处,请多多谅解并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http:/

Android 常用工具类之SPUtil,可以修改默认sp文件的路径

参考: 1. 利用Java反射机制改变SharedPreferences存储路径    Singleton1900 2. Android快速开发系列 10个常用工具类 Hongyang import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; import android.content.SharedPreferences; import java.io.

js常用工具类.

一些js的工具类 复制代码 /** * Created by sevennight on 15-1-31. * js常用工具类 */ /** * 方法作用:[格式化时间] * 使用方法 * 示例: * 使用方式一: * var now = new Date(); * var nowStr = now.dateFormat("yyyy-MM-dd hh:mm:ss"); * 使用方式二: * new Date().dateFormat("yyyy年MM月dd日");

[C#] 常用工具类——文件操作类

/// <para> FilesUpload:工具方法:ASP.NET上传文件的方法</para> /// <para> FileExists:返回文件是否存在</para> /// <para> IsImgFilename:判断文件名是否为浏览器可以直接显示的图片文件名</para> /// <para> CopyFiles:复制指定目录的所有文件</para> /// <para> MoveFi

[C#] 常用工具类——直接在浏览器输出数据

/// <summary> /// <para> </para> /// 常用工具类——直接在浏览器输出数据 /// <para> -------------------------------------------------------------</para> /// <para> DumpDataTable:接在浏览器输出数据DataTable</para> /// <para> DumpListIt

c#常用工具类:文件和二进制转换

//================二进制相关转换类============== #region 将文件转换为二进制数组 /// <summary> /// 将文件转换为二进制数组 /// </summary> /// <param name="FilePath">文件完整路径</param> /// <returns>二进制数组</returns> public static byte[] FileToBinar

java常用工具类(java技术交流群57388149)

package com.itjh.javaUtil; import java.util.ArrayList; import java.util.List; /** * * String工具类. <br> * * @author 宋立君 * @date 2014年06月24日 */ public class StringUtil { private static final int INDEX_NOT_FOUND = -1; private static final String EMPTY =