1. 等待多线程完成的CountDownLatch

CountDownLatch允许一个或多个线程等待其他线程完成操作。

1.1 应用场景

假如有这样一个需求:我们需要解析一个Excel里多个sheet的数据,此时可以考虑使用多
线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。

1.2 CountDownLatch实现原理

 public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);}

CountDownLatch 的await方法调用同步锁的acquireSharedInterruptibly()共享式的获取同步状态。当同步状态减少为0,之后阻塞线程被释放。

CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完
成,这里就传入N。当我们调用CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await方法会阻塞当前线程,直到N变成零。由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,只需要把这个CountDownLatch的引用传递到线程里即可。

1.3 使用案例

public class CountDownLatchTest {static CountDownLatch c = new CountDownLatch(2);public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(1);c.countDown();System.out.println(2);c.countDown();}}).start();c.await();System.out.println("3");}}

2. 同步屏障 CyclicBarrier

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

2.1 CyclicBarrier简介

CyclicBarrier有两种用法:

  1. CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。直到同步屏障中的await数量达到构造方法中的值后,同步Barrier屏障释放。
  2. CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties,Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景

2.2 CyclicBarrier的应用场景

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景。例如,用一个Excel保存了用户所有银行流水,每个Sheet保存一个账户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水

public class BankWaterService implements Runnable{private CyclicBarrier cyclicBarrier=new CyclicBarrier(4,this);private ExecutorService executor= Executors.newCachedThreadPool();private ConcurrentHashMap<String,Integer> sheetBankWaterCount=new ConcurrentHashMap<>();private void count(){for (int i = 0; i < 4; i++) {executor.execute(new Runnable() {@Overridepublic void run() {sheetBankWaterCount.put(Thread.currentThread().getName(),1);System.out.println("本次sheet运行结果:"+1);try {cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}});}}@Overridepublic void run() {int result=0;for (Integer integer : sheetBankWaterCount.values()) {result+=integer;}System.out.println("运行结果:"+result);}public void stop(){executor.shutdown();}public static void main(String[] args) {BankWaterService bankWaterService=new BankWaterService();bankWaterService.count();bankWaterService.stop();}
}

2.3 CyclicBarrier和CountDownLatch的区别

  1. CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数器,并让线程重新执行一次。
  2. CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得Cyclic-Barrier阻塞的线程数量。isBroken()方法用来了解阻塞的线程是否被中断。

3. 控制并发线程数的Semaphore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以
保证合理的使用公共资源。

3.1 应用场景

Semaphore可以用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接。

3.2 使用案例

public class SemaphoreTest {private static final int THREAD_COUNT = 30;private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);private static Semaphore s = new Semaphore(10);public static void main(String[] args) {for (int i = 0; i < THREAD_COUNT; i++) {threadPool.execute(new Runnable() {@Overridepublic void run() {try {s.acquire();System.out.println("save data");s.release();} catch (InterruptedException e) {}}});}threadPool.shutdown();}
}

3.3 其他方法

  • intavailablePermits():返回此信号量中当前可用的许可证数。
  • intgetQueueLength():返回正在等待获取许可证的线程数。
  • booleanhasQueuedThreads():是否有线程正在等待获取许可证。
  • void reducePermits(int reduction):减少reduction个许可证,是个protected方法。
  • Collection getQueuedThreads():返回所有等待获取许可证的线程集合,是个protected方法。

4. 线程间交换数据的Exchanger

Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过
exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。

4.1 应用场景

  1. Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时候会交换两人的数据,并使用交叉规则得出2个交配结果
  2. Exchanger也可以用于校对工作,比如我们需要将纸制银行流水通过人工的方式录入成电子银行流水,为了避免错误,采用AB岗两人进行录入,录入到Excel之后,系统需要加载这两个Excel,并对两个Excel数据进行校对.

4.2 应用案例

public class ExchangerTest {private static final Exchanger<String> exgr       = new Exchanger<String>();private static ExecutorService         threadPool = Executors.newFixedThreadPool(2);public static void main(String[] args) {threadPool.execute(new Runnable() {@Overridepublic void run() {try {String A = "银行流水A";// A录入银行流水数据String exchangeB = exgr.exchange(A);System.out.println("收到线程B传来的数据:"+exchangeB);} catch (InterruptedException e) {}}});threadPool.execute(new Runnable() {@Overridepublic void run() {try {String B = "银行流水B";// B录入银行流水数据String A = exgr.exchange(B);System.out.println("A和B数据是否一致:" + A.equals(B) + ",A录入的是:" + A + ",B录入是:" + B);} catch (InterruptedException e) {}}});threadPool.shutdown();}
}

Java高并发编程(十):Java并发工具类相关推荐

  1. java并发编程中常用的工具类 Executor

    /***************************************************  * TODO: description .  * @author: gao_chun  * ...

  2. java并发编程实践_Java并发编程实践如何正确使用Unsafe

    一.前言 Java 并发编程实践中的话: 编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各 ...

  3. 【Java并发编程】Java多线程(四):FutureTask 源码分析

    前言:[Java并发编程]Java多线程(三):Runnable.Callable --创建任务的方式 在上一篇文章的末尾我们通过两个问题,引出了 FutureTask 及其设计思路,先来回顾一下: ...

  4. 视频教程-Java并发编程实战-Java

    Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...

  5. JUC并发编程(java util concurrent)(哔站 狂神说java juc并发编程 摘录笔记)

    JUC并发编程(java util concurrent) 1.什么是JUC JUC并不是一个很神秘的东西(就是 java.util 工具包.包.分类) 业务:普通的线程代码 Thread Runna ...

  6. java 线程工厂_Java并发编程:Java的四种线程池的使用,以及自定义线程工厂

    引言 通过前面的文章,我们学习了Executor框架中的核心类ThreadPoolExecutor ,对于线程池的核心调度机制有了一定的了解,并且成功使用ThreadPoolExecutor 创建了线 ...

  7. java雪崩_【并发编程】java 如何解决redis缓存穿透、缓存雪崩(高性能示例代码)...

    [并发编程]java 如何解决redis缓存穿透.缓存雪崩(高性能示例代码) 发布时间:2018-11-22 16:48, 浏览次数:872 , 标签: java redis <>缓存穿透 ...

  8. 【并发编程十九】芊程(fiber)

    [并发编程十九]芊程(fiber) 一.前言 二.芊程(fiber) 1.线程中使用芊程 2.获取当前芊程数据 3.从芊程切回线程 4.创建新的芊程 5.删除芊程对象 6.在不同芊程间切换 7.芊程局 ...

  9. java 手机号脱敏,身份证号脱敏 工具类

    java 手机号脱敏,身份证号脱敏 工具类 import org.apache.commons.lang3.StringUtils;/*** * @title: 脱敏工具类* @author: wll ...

  10. java将链接生成二维码工具类

    一.添加依赖 <!-- 生成二维码--><dependency><groupId>com.google.zxing</groupId><artif ...

最新文章

  1. MindSpore API编程概述
  2. Linux zip-tar.gz 压缩解压
  3. java 判断ocx是否存在_OCX控件的注册卸载,以及判断是否注册
  4. Django使用已经存有数据的mysql数据库
  5. matlab学习——1.基本操作
  6. Git学习笔记03--git reset
  7. 将 Sidecar 容器带入新的阶段
  8. android 根据版本,Android – 根据构建类型更改flavor版本名称
  9. 多个装饰器装饰一个函数
  10. oracle块空间的使用,Oracle管理存储架构(二)--Oracle管理数据块空间
  11. 密码学专题 OpenSSL专题
  12. 64位linux安装mysql数据库吗_Linux下安装Mysql数据库
  13. 深入解析 Go 中 Slice 底层实现
  14. android UI之去掉状态栏
  15. Java分代垃圾回收机制:年轻代/年老代/持久代(转)
  16. Java常见排序算法之快速排序详解
  17. 【多元统计分析】11.回归方程与回归系数的显著性检验
  18. 机器周期、指令周期、时钟周期、总线周期
  19. CDA Level1知识点总结之业务分析报告与数据可视化报表
  20. 崩坏3服务器维护2月8号,崩坏3影骑士月轮将在2月8日更新后正式登场

热门文章

  1. mysql客户端( Navicat)远程登录操作问题 1142-create command denied to user×××
  2. 【POJ 3273】 Monthly Expense (二分)
  3. 清除XCode缓存和生成文件
  4. 从30岁到35岁:为你的生命多积累一些厚度(转)
  5. 【转】高性能前端3-高性能javascript
  6. struts——struts在升级,作为程序员,该怎样以不变应万变?
  7. Asp.net 2.0 制作复合控件示例(二)[示例代码下载]
  8. Windows程序设计:MFC 、Winform 和 WPF 比较
  9. 计算机视觉开源库OpenCV之平滑、模糊和滤波
  10. Linux源码安装步骤