当达到人数未符合预期,则不能正常上课,目前看已经满足我们的需求了。那我们紧接着模拟一下学生迟到的场景~
依然是学号为 10 的同学,虽迟但到,课还是可以正常进行上的!
看来 CountDownLatch 真是一个好工具,简简单单就帮我们解决了该问题!那他怎么解决的呢?
CountDownLatch 是通过一个计数器来实现的,首先设置一个计数器的初始值。每当完成一个任务后,计数器的值就会减1,当计数器达到0
时,它表示所有任务都已经完成,然后在闭锁上等待的线程可以恢复执行任务.
我们首先可以要看的是 CountDownLatch 的构造方法
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException(“count < 0”);
this.sync = new Sync(count);
}
该方法需要初始化一个计数值,并初始化一个 Sync
, 我们这个时候不妨大胆猜测,CountDownLatch
底层便是靠 Sync
实现的!我们来看看 Sync 是个啥玩意?
可以看到在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 的CountDownLatch,并让所有线程都在这个锁上等待,那么我们就可以很轻松的完成测试,只需要调用一次 **countDown()**方法就可以让所有等待线程同时恢复执行
- 开始执行前等待 n 个线程完成各自的任务
当我们应用程序执行前,确保某些前置动作需要执行
- 死锁检测
我们可以使用 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 还是有点类似的,但是我们要清楚他们之间的区别:
-
CountDownLatch: 一个线程(或多个),等待另外 N 个线程完成某件事情之后才会执行
-
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);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://img-blog.csdnimg.cn/img_convert/df105a8e6d844962cee4cfee11715669.jpeg)
总结
虽然我个人也经常自嘲,十年之后要去成为外卖专员,但实际上依靠自身的努力,是能够减少三十五岁之后的焦虑的,毕竟好的架构师并不多。
架构师,是我们大部分技术人的职业目标,一名好的架构师来源于机遇(公司)、个人努力(吃得苦、肯钻研)、天分(真的热爱)的三者协作的结果,实践+机遇+努力才能助你成为优秀的架构师。
如果你也想成为一名好的架构师,那或许这份Java成长笔记你需要阅读阅读,希望能够对你的职业发展有所帮助。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
实际上依靠自身的努力,是能够减少三十五岁之后的焦虑的,毕竟好的架构师并不多。
架构师,是我们大部分技术人的职业目标,一名好的架构师来源于机遇(公司)、个人努力(吃得苦、肯钻研)、天分(真的热爱)的三者协作的结果,实践+机遇+努力才能助你成为优秀的架构师。
如果你也想成为一名好的架构师,那或许这份Java成长笔记你需要阅读阅读,希望能够对你的职业发展有所帮助。
[外链图片转存中…(img-trEt7u2H-1713516027138)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!