Java并发工具篇
theme: juejin
highlight: an-old-hope
作者:汤圆
个人博客:javalover.cc
前言
随着天气的逐渐变热,整个人也开始浮躁不安
当然这里说的不是我,因为我是一个比较安静的人
讲的是隔壁的老大哥,在训斥年幼的孩子
一通吼叫过后,男人安静了下来,孩子也哭个不停
简介
前面我们介绍了 JUC 中的并发容器,它相当于一个同步容器的升级版,很大程度上提高了并发的性能
今天我们来介绍 JUC 中的并发工具,它主要是通过改变自身的状态来控制线程的执行流程;
常见的有如下几种:
- CountDownLatch:倒计时器(属于闭锁的一种实现),用来阻塞线程
- CyclicBarrier:循环栅栏,类似倒计时器,但是比他更高级,也是用来阻塞线程(只不过阻塞的方式不同,下面会具体介绍)
- Semaphore:信号量,用来控制多个线程同时访问指定的资源,比如我们常用的数据库连接池
下面让我们开始吧
文章如果有问题,欢迎大家批评指正,在此谢过啦
目录
- 什么是并发工具
- 倒计数器 CountDownLatch
- 倒计数器升级版 CyclicBarrier【循环栅栏】
- 信号量 Semaphore
- 区别
正文
1. 什么是并发工具
并发工具是一组工具类,主要是用来控制线程的执行流程,比如阻塞某个线程,以等待其他线程
2. 倒计数器 CountDownLatch
从字面意思来看,就是一个倒计数门闩(shuan,打了半天zha就是打不出来)
通俗一点来说,就是倒计数,时间一到,门闩就打开
注:一旦打开,就不能再合上,即这个 CountDownLatch 的状态改变是永久不可恢复的(记住这个点,后面会有对比)
比较官方的说法:倒计数器用来阻塞某个(某些)线程,以等待其他多个线程的任务执行完成(以这个说法为准,上面的可以用来对比参考)
下面列出 CountDownLatch 的几个方法:
构造方法:
public CountDownLatch(int count)
,其中count就是我们所说的内部状态(当count=0时,表示到达终止状态,此时会恢复被阻塞的线程)修改状态:
public void countDown()
,该方法会递减上面的count状态,每执行一次,就-1;(当count=0时,表示到达终止状态,此时会恢复被阻塞的线程)等待:
public void await()
,该方法会阻塞当前线程,直到count状态变为0,才会恢复执行(除非中断,此时会抛出中断异常)超时等待:
public boolean await(long timeout, TimeUnit unit)
,类似上面的await,只不过可以设置超时时间,等过了超时时间,还在阻塞,则直接恢复获取状态值 count:
public long getCount()
,获取count的数值,以查看还可以递减多少次(多用来调试)
模拟场景的话,这里先列举三个,肯定还有其他的
- 第一个就是计数器了,最直接的
- 第二个就是统计任务执行时长
- 第三个就是多人5V5游戏,等所有人加载完毕,就开始游戏
下面我们以第三个场景为例,写个例子:多人游戏加载画面
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 构造一个倒计数器,给定一个状态值10
CountDownLatch latch = new CountDownLatch(10);
System.out.println("准备加载");
// 这里我们创建10个线程,模拟 5V5 游戏的10个玩家
for (int i = 0; i < 10; i++) {
new Thread(()->{
// 这里我们给点延时,模拟网络延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"加载100%");
// 2. 这里的countDown就是用来改变倒计数器的内部状态,每次-1
latch.countDown(); //这里不会阻塞当前线程,执行完后就立马返回了
}).start();
}
// 3. 这里阻塞等待状态的完成,即10变为0;
latch.await();
System.out.println("所有人加载完成,开始游戏");
}
}
输出如下:
准备加载
Thread-0加载100%
Thread-1加载100%
Thread-2加载100%
Thread-3加载100%
Thread-4加载100%
Thread-5加载100%
Thread-6加载100%
Thread-8加载100%
Thread-9加载100%
Thread-7加载100%
所有人加载完成,开始游戏
这里倒计数器的作用就是阻塞主线程,以等待其他10个子线程,等到都准备好,再恢复主线程
它的特点就是:一次性使用,达到终止状态后不能再改变
3. 倒计数器升级版 CyclicBarrier【循环栅栏】
循环栅栏,类似倒计数器,也是用来阻塞线程,不过它的重点在于循环使用
而倒计数器只能用一次(这属于他们之间最明显的一个区别)
PS:猜测之所以叫循环栅栏,而不是循环门闩,可能是因为栅栏的作用比门闩更强大,所以叫栅栏更适合吧
官方说法:循环栅栏一般用来表示多个线程之间的相互等待(阻塞)
比如有10个线程,都要await等待;那要等到最后一个线程await时,栅栏才会打开
如果有定义栅栏动作,那么当栅栏打开时,会执行栅栏动作
栅栏动作就是:栅栏打开后需执行的动作,通过构造函数的Runnable参数指定,可选参数,下面会介绍
这个属于循环栅栏和倒计数器的第二个区别:
- 循环栅栏强调的是多个被阻塞线程之间的相互协作关系(等待)
- 而倒计数器强调的是单个(或多个)线程被阻塞,来等待其他线程的任务执行
下面我们看几个循环栅栏 CyclicBarrier 内部的方法:
- 构造方法:
public CyclicBarrier(int parties, Runnable barrierAction)
,第一个表示需等待(阻塞)的线程数,第二个barrierAction就是上面我们说的栅栏动作,即当最后一个线程也被阻塞时,就会触发这个栅栏动作(这个参数可选,如果没有,则不执行任何动作) - 等待:
public int await()
,阻塞当前线程,直到最后一个线程被阻塞,才会恢复 - 超时等待:
public boolean await(long timeout, TimeUnit unit)
,类似上面的await,只不过可以设置超时时间 - 获取当前等待的线程数:
public int getNumberWaiting()
,即调用了await方法的线程数量
场景:
大事化小,小事合并:就是将某个大任务拆解为多个小任务,等到小任务都完成,再合并为一个结果
多人对战游戏团战
- 上面的倒计数器表示游戏开始前的准备工作(只需准备一次)
- 而这里的循环栅栏则可以表示游戏开始后的团战工作(可团战多次)
下面看下例子:多人游戏团战画面
public class CyclicBarrierDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 创建一个循环栅栏,给定等待线程数10和栅栏动作
CyclicBarrier barrier = new CyclicBarrier(10,()->{
// 栅栏动作,等到所有线程都await,就会触发
System.out.println("=== 人齐了,开始团吧");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("=== 准备第一波团战 ===");
// 2. 创建10个线程,模拟10个玩家
for (int i = 0; i < 10; i++) {
new Thread(()->{
try {
// 玩家到场
System.out.println(Thread.currentThread().getName()+"=>第一波团,我准备好了");
// 等待其他人,等人齐就可以团了(人齐了会执行栅栏动作,此时这边也会恢复执行)
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
// 3. 查询当前等待都线程数量,如果不为0,则主线程继续等待
while (barrier.getNumberWaiting()!=0){
Thread.sleep(1000);
}
System.out.println("=== 第一波团战结束 ===");
// 4. 此时还可以进行第二波第三波团战。。。(循环栅栏可循环触发,倒计数器只能触发一次)
}
}
输出如下:
=== 准备第一波团战 ===
Thread-0=>第一波团,我准备好了
Thread-1=>第一波团,我准备好了
Thread-2=>第一波团,我准备好了
Thread-3=>第一波团,我准备好了
Thread-4=>第一波团,我准备好了
Thread-5=>第一波团,我准备好了
Thread-6=>第一波团,我准备好了
Thread-7=>第一波团,我准备好了
Thread-8=>第一波团,我准备好了
Thread-9=>第一波团,我准备好了
=== 人齐了,开始团吧
=== 第一波团战结束 ===
4. 信号量 Semaphore
信号量主要是用来控制多个线程同时访问指定资源,比如数据库连接池,超过指定数量,就阻塞等待
下面我们介绍下信号量的几个关键方法:
- 构造方法:
public Semaphore(int permits, boolean fair)
,第一个参数为许可数,即允许同时访问的的线程数,第二个参数为公平还是非公平模式(默认非公平)- 公平模式,谁先调用acquire,谁就先访问资源,FIFO先进先出
- 非公平模式,允许插队,如果某个线程刚释放了许可,另一个线程就调用了acquire,那么这个线程就会插队访问资源)
- 获取许可:
public void acquire()
,如果有许可,则直接返回,并将许可数递减1;如果没可用的许可,就阻塞等待,或者被中断 - 尝试获取许可:
public boolean tryAcquire()
,类似上面的acquire,但是不会被阻塞和中断,因为如果没有可用的许可,则直接返回false - 释放许可:
public void release()
,释放一个许可,并将许可数递增1 - 获取可用的许可数量:
public int availablePermits()
,这个方法一般用来调试
场景:数据库连接池
信号量的特点就是可重复使用许可,所以像数据库连接池这种场景就很适合了
这里就不举例子了,就是多个线程acquire和release,获取许可时,如果没有就阻塞,如果有就立即返回
5 区别
用表格看比较方便点
区别 | CountDownLatch | CyclicBarrier | Semaphore |
---|---|---|---|
可使用次数 | 单次 | 多次(循环使用) | 多次(循环使用) |
线程的阻塞 | 阻塞单个(多个)线程,以等待其他线程的执行 | 多个线程之间的相互阻塞 | 超过许可数,会阻塞 |
场景 | 1. 计数器 2. 统计任务执行时长 3. 多人对战游戏的开局等待 |
1. 大事化小,再合并 2. 多人对战游戏的团战 |
1. 数据库连接池 |
可以看到,倒计数器主要是用来表示单个线程等待多个线程,而循环栅栏主要是用来表示多个线程之间的相互等待
总结
- 什么是并发工具:并发工具是一组工具类,主要是用来控制线程的执行流程,比如阻塞某个线程,以等待其他线程
- 倒计数器 CountDownLatch:用来表示阻塞某个(某些)线程,以等待其他多个线程的任务执行完成
- 循环栅栏 CyclicBarrier:用来表示多个线程之间的相互等待协作(阻塞)
- 信号量 Semaphore:用来表示允许同时访问指定资源的许可数(线程数)
- 区别:
区别 | CountDownLatch | CyclicBarrier | Semaphore |
---|---|---|---|
可使用次数 | 单次 | 多次(循环使用) | 多次(循环使用) |
线程的阻塞 | 阻塞单个(多个)线程,以等待其他线程的执行 | 多个线程之间的相互阻塞 | 超过许可数,会阻塞 |
场景 | 1. 计数器 2. 统计任务执行时长 3. 多人对战游戏的开局等待 |
1. 大事化小,再合并 2. 多人对战游戏的团战 |
1. 数据库连接池 |
参考内容:
- 《Java并发编程实战》
- 《实战Java高并发》
后记
学习之路,真够长,共勉之
写在最后:
愿你的意中人亦是中意你之人
Java并发工具篇的更多相关文章
- Linux工具XFTP、Xshell(centos配置java环境 工具篇 总结一)
♣Xmanager5是什么? ♣安装XFTP ♣安装Xshell 1.Xmanager5(官网:https://www.netsarang.com/download/software.html)是全新 ...
- Java并发工具类 - CountDownLatch
Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...
- 基于AQS实现的Java并发工具类
本文主要介绍一下基于AQS实现的Java并发工具类的作用,然后简单谈一下该工具类的实现原理.其实都是AQS的相关知识,只不过在AQS上包装了一下而已.本文也是基于您在有AQS的相关知识基础上,进行讲解 ...
- 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger
1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...
- Java并发工具类CountDownLatch源码中的例子
Java并发工具类CountDownLatch源码中的例子 实例一 原文描述 /** * <p><b>Sample usage:</b> Here is a pai ...
- Java 并发系列之八:java 并发工具(4个)
1. CountDownLatch 2. CyclicBarrier 3. Semaphore 4. Exchanger 5. txt java 并发工具 通俗理解 CountDownLatch 等A ...
- 【Java并发工具类】Java并发容器
前言 Java并发包有很大一部分都是关于并发容器的.Java在5.0版本之前线程安全的容器称之为同步容器.同步容器实现线程安全的方式:是将每个公有方法都使用synchronized修饰,保证每次只有一 ...
- Java并发容器篇
作者:汤圆 个人博客:javalover.cc 前言 断断续续一个多月,也写了十几篇原创文章,感觉真的很不一样: 不能说技术有很大的进步,但是想法确实跟以前有所不同: 还没开始的时候,想着要学的东西太 ...
- java 并发工具类CountDownLatch & CyclicBarrier
一起在java1.5被引入的并发工具类还有CountDownLatch.CyclicBarrier.Semaphore.ConcurrentHashMap和BlockingQueue,它们都存在于ja ...
随机推荐
- 混合编程:如何用python11调用C++
摘要:在实际开发过程中,免不了涉及到混合编程,比如,对于python这种脚本语言,性能还是有限的,在一些对性能要求高的情景下面,还是需要使用c/c++来完成. 那怎样做呢?我们能使用pybind11作 ...
- Paperfolding HDU - 6822
传送门:https://vjudge.net/problem/HDU-6822 题意:给你一张无限的纸有四种折叠方式,并且在n次折叠后减两刀问最后纸张数量的数学期望. 思路:我们要得到一个通项公式对于 ...
- ResNet的个人总结
ResNet可以说是我认真读过的第一篇paper,据师兄说读起来比较简单,没有复杂的数学公式,不过作为经典的网络结构还是有很多细节值得深究的.因为平时不太读英文文献,所以其实读的时候也有很多地方不是很 ...
- PTA 数组元素的区间删除
6-6 数组元素的区间删除 (20 分) 给定一个顺序存储的线性表,请设计一个函数删除所有值大于min而且小于max的元素.删除后表中剩余元素保持顺序存储,并且相对位置不能改变. 函数接口定义: ...
- juc下Condition类解析
在使用Lock之前,我们使用的最多的同步方式应该是synchronized关键字来实现同步方式了.配合Object的wait().notify()系列方法可以实现等待/通知模式. Condition接 ...
- Android Studio 之创建自定义控件
•前言 常用控件和布局的继承结构,如下图所示: 可以看到,我们所用的所有的控件都是直接或者间接的继承自View的: 所用的所有布局都是直接或者间接继承自ViewGroup的: View 是 Andro ...
- [LeetCode]2. 两数相加(难度:中等)
题目: 给你两个非空的链表,表示两个非负的整数.它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字.请你将两个数相加,并以相同形式返回一个表示和的链表.你可以假设除了数字0之外,这两个 ...
- 基于gitlab的项目管理流程
框架 背景 个人是不太愿意使用用户体验差的软件来做项目管理,行业内,要找到这么一款软件,又要符合自己的需求,着实不容易.要免费,易用性要好,要安全,要有数据统计.而程序员的世界,SVN 之后,可能没有 ...
- Leedcode算法专题训练(数组与矩阵)
1. 把数组中的 0 移到末尾 283. Move Zeroes (Easy) Leetcode / 力扣 class Solution { public void moveZeroes(int[] ...
- 会议更流畅,表情更生动!视频生成编码 VS 国际最新 VVC 标准
阿里云视频云的标准与实现团队与香港城市大学联合开发了基于 AI 生成的人脸视频压缩体系,相比于 VVC 标准,两者质量相当时可以取得 40%-65% 的码率节省,旨在用最前沿的技术,普惠视频通话.视频 ...