博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
举例详解 java.util.concurrent 并发包 4 种常见类
阅读量:4136 次
发布时间:2019-05-25

本文共 6441 字,大约阅读时间需要 21 分钟。

目录

JUC

具体就是指 :java.util.concurrent 的并发包

1. 可重入互斥锁 ReentrantLock

作用

保证线程安全,和sychronized使用差不所

常用方法

ReentrantLock():构造方法,参数为true则为公平锁,默认非公平锁

lock():加锁
unlock():释放锁

代码举例

//全局变量    private static int number = 0;    //循环次数    private static final int maxSize = 100000;    public static void main(String[] args) throws InterruptedException {
//1.创建手动锁 Lock lock = new ReentrantLock(); //+10w Thread t1 = new Thread(new Runnable() {
@Override public void run() {
for (int i = 0; i < maxSize; i++) {
//2.加锁 lock.lock(); try {
number++; }finally {
//3.释放锁 lock.unlock(); } } } }); t1.start(); //-10w Thread t2 = new Thread(new Runnable() {
@Override public void run() {
for (int i = 0; i < maxSize; i++) {
lock.lock(); try {
number--; }finally {
lock.unlock(); } } } }); t2.start(); //等t1,t2线程执行完 t1.join(); t2.join(); System.out.println("运行结果为:" + number); }

最后输出0,线程安全

注意事项:

(1)lock 写在 try 之前
(2)一定要记得在 finally 里面进行 unlock()

2. 信号量 Semaphore

作用

用来控制锁的数量

常见方法

Semaphore():构造方法,可以设置信号量个数,以及是否为公平锁

acquire() :尝试获取锁,如果可以正常获取到,则执行后面的业务逻辑,如果获取失败,则阻塞等待
release() :释放锁

代码举例

我们构造4辆车,以及2个停车位,让4辆车进入2个停车位,用到Semaphore信号量

public static void main(String[] args) {
//创建信号量 Semaphore semaphore = new Semaphore(2); //线程池执行一个任务相当于一辆车进入停车场 ThreadPoolExecutor executor = new ThreadPoolExecutor(10,10,0, TimeUnit.SECONDS,new LinkedBlockingQueue<>(100)); for (int i = 0; i < 4; i++) {
//创建任务1 executor.execute(new Runnable() {
@Override public void run() {
System.out.println(Thread.currentThread().getName() + " 到达停车场"); try {
Thread.sleep(1000); } catch (InterruptedException e) {
e.printStackTrace(); } //试图进入车位 try {
//尝试获取锁 semaphore.acquire(); //当代码执行到此处说明已经获取到了锁 System.out.println(Thread.currentThread().getName() + " 进入车位----"); //车辆停留的时间构建 int num = 1 + new Random().nextInt(5); try {
Thread.sleep(num * 1000); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "离开停车场。。。。"); } catch (InterruptedException e) {
e.printStackTrace(); }finally {
//释放锁 semaphore.release(); } } }); } }

在这里插入图片描述

可以看到,始终只有2辆车占用停车位,哪个车走了,停车位让出来了,后面的车才能进入

从而就实现了流量控制

3. 计数器 CountDownLatch

作用

计数器是用来保证一组线程同时完成某个任务

常用方法

CountDownLatch():构造方法,参数为n个线程

await() :等待,当线程数量不满足 CountDownLatch 的数量的时候,执行此代码会阻塞等待,直到数量满足之后,再执行 await 之后的代码
countDown():计数器数量-1

实现原理

在 CountDownLatch 里面有一个计数器,每次调用countDown() 方法的时候,计数器数量-1,直到减到 0 之后,就可以执行 await() 之后的代码了

代码实例

设置5个人同时起跑,每到达终点一个人,计数器-1,最后计数器为0时,公布成绩

public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(5); for (int i = 1; i < 6; i++) {
int finalI = i; new Thread(new Runnable() {
@Override public void run() {
System.out.println(Thread.currentThread().getName() + "开始起跑"); try {
Thread.sleep(finalI * 1000); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "到达终点"); //计数器-1 latch.countDown(); } }).start(); } //阻塞等待 latch.await(); System.out.println("所有人都到达了终点,公布排名"); }

在这里插入图片描述

由此可见,当计数器没到0之前,就会阻塞等待,到0后,则执行await后面的代码

缺点

CountDownLatch 计时器的使用是一次性的,当用完一次后,就不能再使用了

4. 循环屏障 CyclicBarrier

作用

也是计时器,不过这个可以解决CountDownLatch的缺点,可以多次进行计数

常用方法

CyclicBarrier(int,Runnable):在int线程计数器为0时,继续执行runnable方法

await():等待,(1)计数器 -1 (2)判断计数器是否为 0,如果为 0 执行之后的代码,如果不为 0 阻塞等待
PS:当计数器为 0 时,首先会执行 await 之后的代码,将计数器重置

代码举例

和上面计数器例子一样,不过这时候10个线程起跑,需要每5个人记录一下时间

public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override public void run() {
System.out.println("执行了CyclicBarrier里面的Runnable"); } }); for (int i = 1; i < 11; i++) {
int finalI = i; new Thread(new Runnable() {
@Override public void run() {
System.out.println(Thread.currentThread().getName() + "开始起跑"); try {
Thread.sleep(1000 * finalI); } catch (InterruptedException e) {
e.printStackTrace(); } // try {
System.out.println(Thread.currentThread().getName() + "等待其他人---"); //计数器-1,判断计数器是否为0 cyclicBarrier.await(); } catch (InterruptedException e) {
e.printStackTrace(); } catch (BrokenBarrierException e) {
e.printStackTrace(); } // 代码执行到此行,说明已经有一组线程满足条件了 System.out.println(Thread.currentThread().getName() + "执行结束。。。"); } }).start(); } }

在这里插入图片描述

可以看到此类可以循环的计数,每次计数器为0时,又将计数器置为初始值
在这里插入图片描述

CyclicBarrier 和 CountDownLatch 区别

  • CountDownLatch 计数器只能使用一次;
  • CyclicBarrier 他的计数器可以重复使用;

转载地址:http://pixvi.baihongyu.com/

你可能感兴趣的文章
qml有关矩形说明
查看>>
在qt中使用QSplitter设置初始比例setStretchFactor失效的解决方法
查看>>
repeater的使用
查看>>
qt msvc编译中文乱码解决
查看>>
qt中TextField输入框无法输入中文解决办法
查看>>
qt实现点击出现窗口,点击其他任何地方窗口消失
查看>>
QML DropArea拖拉文件事件
查看>>
CORBA links
查看>>
读后感:&gt;
查看>>
ideas about sharing software
查看>>
different aspects for software
查看>>
To do list
查看>>
Study of Source code
查看>>
如何使用BBC英语学习频道
查看>>
spring事务探索
查看>>
浅谈Spring声明式事务管理ThreadLocal和JDKProxy
查看>>
初识xsd
查看>>
java 设计模式-职责型模式
查看>>
构造型模式
查看>>
svn out of date 无法更新到最新版本
查看>>