《吃透Java》- 并发何须惧,工具来相助(2)

图片

可以看到在Sync内部维护着一个安全变量 state,它的值便是 计数器的值。其中有两个重要方法:tryAcquireShared(int acquires) 和 tryReleaseShared(int releases)。那这两个方法有什么用呢?

我们可以先回到 CountDownLatch 类中,上面我们已经看到该类构造函数的作用,接下来需要认识其中两个重要的方法:countDown() 和 await()。在我们看来,countDown() 方法便是用来将计数值减 1, await() 方法是用来阻塞判断计数值是否为 0?那我们进入对应方法看是如何实现的

public void countDown() {

sync.releaseShared(1);

}


public void await() throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

这两个方法调用的都是 AQS 中的两个方法:(我这边直接贴源码注释,仔细看哦~!)

countDown()

图片

await()

图片

上面便是 CountDownLatch 的实现,那我们不妨想想该工具类在实时系统中的使用场景:

  1. 实现最大的并行性

当我们想要同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类,如果我们创建一个初始值为 1 的CountDownLatch,并让所有线程都在这个锁上等待,那么我们就可以很轻松的完成测试,只需要调用一次 **countDown()**方法就可以让所有等待线程同时恢复执行

  1. 开始执行前等待 n 个线程完成各自的任务

当我们应用程序执行前,确保某些前置动作需要执行

  1. 死锁检测

我们可以使用 n 个线程访问共享资源,在每次测试阶段的线程数目是不同的,这样可以尝试产生死锁

二、CyclicBarrier

CyclicBarrier是另外一种多线程并发控制工具。Cyclic 意为循环,也就是说这个计数器可以反复使用,它比CountDownLatch更加强大一点,它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程达到屏障时,屏障才会开门,所有被屏障拦截的线程才会继续工作。

也就是说 CyclicBarrier 是加法计时器,我们一样通过以上 《一个都不能少》 例子来示例如何使用

图片

这里就不再演示缺课与迟到的示范,与上述 CountDownLatch 实现方式一致

这里我们依然关注两个方法,一个是构造方法,一个是 await()

我们依然进入到 CyclicBarrier 类中查看构造方法

public CyclicBarrier(int parties, Runnable barrierAction) {

if (parties <= 0) throw new IllegalArgumentException();

this.parties = parties;

this.count = parties;

this.barrierCommand = barrierAction;

}

可以发现和上面说到的 CountDownLatch 还是有出入的,该构造方法只是做了屏障点的记录,我们重点还是要看 await() 方法

public int await() throws InterruptedException, BrokenBarrierException {

try {

return dowait(false, 0L);

} catch (TimeoutException toe) {

throw new Error(toe); // cannot happen

}

}

追根朔底我们得看 dowait() 方法,进入方法可以发现实现方式并不复杂。由于代码有点长,我们截取重点说明

与 CountDownLatch 不同的是,屏障点变量并没有使用 volatile 修饰,那么毋庸就得加锁使之线程安全!

图片

图片

图片

以上便是 CyclicBarrier 的整个实现过程,具体咱就不抠细节了~!

CyclicBarrier 和 CountDownLatch 还是有点类似的,但是我们要清楚他们之间的区别:

  1. CountDownLatch: 一个线程(或多个),等待另外 N 个线程完成某件事情之后才会执行

  2. CyclicBarrier: N 个线程之间相互等待,任何一个线程完成之前,所有的线程都必须等待

比较重要的一点:CountDownLatch 不可重复利用,CyclicBarrier 不可重复利用

三、Semaphore

信号量(Semaphore)是为多线程提供了更为强大的控制方法。从广义上来讲,信号量是对锁的扩展。无论是内部锁synchronized还是重入锁ReentrantLock,一次都只允许一个线程访问一个资源,而信号量却可以指定多个线程,同时访问某一个共享资源。

我们简单看个简易的例子

《抢车位》

原本一个小区有 5 个地上停车位已经可以很好的满足业主的停车需求,但是这两年车辆数暴增,几乎家家一车,车位自然供不应求,那只能遵循先到先得的原则!

图片

然后我们看下执行结果:

图片

可以看到 5 个车位是共享资源,只有先到的业主才能抢到车位,当抢到车位的业主离开后,后续的业主才能进入获取到车位!

我们提取出关注点构造方法acquire()release()

构造方法

public Semaphore(int permits) {

sync = new NonfairSync(permits);

}

public Semaphore(int permits, boolean fair) {

sync = fair ? new FairSync(permits) : new NonfairSync(permits);

}

是的,Semaphore 有两个构造方法,区别在于是否使用公平锁。然后我们继续看 aquire()release()

public void acquire() throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

public void release() {

sync.releaseShared(1);

}

excuse me~? 前面有认真看的小伙伴,肯定觉得眼熟了,这调用的方法岂不是和上面 CountDownLatch 的一样?是的,这两个并发工具类,底层都是 调用 AQS 的线程方法。如果不知道这两个方法作用的同学,可以上翻查看,这里不再赘述!

根据这个工具类结合上述例子,我们可以在流量控制的时候使用!特别是公共资源有限的应用场景,比如数据库连接,假如有一个需求要读取几万个文件的数据,因为都是 IO 密集型的任务,我们可以启动几十个线程去并发地读取,但是我们得经过硬盘->内存->数据库,而如果数据库的连接数只有10个,那我们这个时候就必须要控制只有 10 个线程可以同时获取数据库连接保存数据,这个时候就可以使用 Semaphore 来做流量控制~!

四、Exchanger

看到这个名称,不知道有多少小伙伴脑子里想的是 这是啥?。实话说,这个工具类出镜率真不高,用的比较少。Exchanger 是一个用于线程间协作的工具类。它可用于线程间的数据交换,它提供了一个同步点,两个线程可以交换彼此的数据,。这两个线程通过 Exchanger 方法交换数据,如果第一个线程先执行 exchange() 方法, 它会一直等待第二个线程也执行 exchanger() 方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。

这里注意的是 两个线程,不存在**“三角关系”**

图片

在没有经过 exchange() 时,数字线程 打印的应该是数字,字母线程打印的应该是字母,但是经过了 exchange()结果就发生了逆转:

图片

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
unity.csdnimg.cn/images/e5c14a7895254671a72faed303032d36.jpg" alt=“img” style=“zoom: 33%;” />

最后

[外链图片转存中…(img-Bj3r52Wl-1713515988624)]

[外链图片转存中…(img-MnYc83Zs-1713515988625)]

[外链图片转存中…(img-wPEr7r05-1713515988626)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值