并发协同
多个线程并发,协作来完成一件事情的过程中,因事情处理的需要,需控制某些线程来阻塞,等待另一些线程来完成某部分事情,再继续执行的过程
应用场景
会话
实现方式
多线程协同都基于条件等待-通知模式
- 基于传统的 synchronized 及 Oject的 wait、notify/notifyAll 监听器的方式
- 基于 Lock 及 Condition 的 await、singal 方式的 等待-通知
- 用Java并发包提供的API
并发协同的常用类
- CountDownLatch 倒计数锁存器
- CyclicBarrier 循环屏障/循环栅栏
- Phaser 阶段协同器/相位器
- Semaphore 计数信息量
倒计数锁存器
Java 1.5 引入的一个工具类
创建对象时,传入指定参数值,作为参与的线程数或者等待执行的任务数
主要包含
await : 方法等待计数器值变为0,在这之前,想成进入等待状态
countDown : 计数器数值每次减1,直到0为止
注意:每个 CountDownLatch 对象,只可以使用一次,计数变为0后,就不可在用了
经常用于一个或多个线程等待其他线程的操作完成,在执行下一步操作
应用场景:
- 统计线程的执行情况
- 压力测试中,使用countDownLatch实现最大程度的并发案处理
- 多个线程之间,相互通信,比如:线程异步调动完接口,结果通知
循环屏障/循环栅栏
Java 1.5引入的一个工具类
创建对象时,要执行栅栏线程的数量
主要包含
await: 等指定数量的线程都出于等待状态时,继续执行后续代码
barrierAction:线程数量到了指定量之后,自动触发执行指定任务
注意:
- 要确保有足够的线程参与,否则会有线程一直出于阻塞
- 在线程池中使用需要确保 池容纳的数量>= 要求的参与数
与 CountDownLatch 区别
- CountDownLatch是一部分线程等待另一部分线程来唤醒
- CyclicBarrier是参与的线程彼此等待
- CyclicBarrier对象可多次触发执行
典型场景
- 请求合并,批量处理
- 聚合计算(比如数据统计。利用30个线程计算30天的数据,全部统计完成后,汇总)
阶段协同器/相位器
Java 1.7中增加的一个用于多阶段同步控制的工具类,他包含了CyclicBarrier 和 CountDownLatch 的相关功能
多个线程协作执行的任务分为多个阶段,每个阶段都可以有任意个参与者,线程可以随时注册并参与到某个阶段;当一个阶段中多个任务都可以成功完成后,phaser的onAdvance()被调用(可以通过覆盖添加自定义处理逻辑【类似栅栏使用的runable接口】)然后通过phaser释放等待线程,自动进入下一个阶段。如此循环,直到phaser不在包含任何参与者
主要包含
parties 组成的个数
phase 进入的阶段
arrives 已经处于等待状态的数量
awaits 当前正在等待的数量
注意:主要保证线程的安全性,可能因为某些线程没有完成,但是别的线程参与了进来代替了计数
计算信息量
又称“信号量”,控制多个线程争抢许可
主要包含
acquire 获取一个许可,如果没有就等待
release 释放一个许可
availablePermits 可以得到许可数目
典型场景
- 代码并发处理限流