转载自  三个好用的并发工具类

以前的文章中,我们介绍了太多的底层原理技术以及新概念,本篇我们轻松点,了解下 Java 并发包下、基于这些底层原理的三个框架工具类。

它们分别是:

  • 信号量 Semaphore

  • 倒计时门栓 CountDownLatch

  • 屏障 CyclicBarrier

所以,既然是工具类,那么必然是离不开特定的场景的,于是相互之间没有谁优谁劣,只有谁更合适。

信号量 Semaphore

Semaphore 适用于什么样的使用场景呢,我们举个通俗的例子:

假如现在有一个停车场,里面有只十个停车位,当着十个停车位都被占用了,外面的车就不允许进入了,就必须在外面等着。出来一辆车才允许进去一辆车

这个场景不同于我们一般的并发场景,一般来说,我们的临界资源只能允许一个线程进行访问,其他线程都地等着。

但是,有一种场景是,临界资源允许多个线程同时访问,超过限定数量的外的线程得阻塞等待。

这种情境使用原始的那一套也是能实现的,但那叫「造轮子」,Java 并发框架下给我们提供了一个工具类,专门适用这种场景。

Semaphore 可以说是为上述这种场景而生的一个工具类,我们写个 demo 实现上述逻辑:

执行程序之后,你会看到:

你看,出来一个线程才允许进去一个线程,这就是 Semaphore。

semaphore 的内部原理其实你去看源码,你会发现和我们的 ReentrantLock 的实现是极其类似的,包括公平与非公平策略的支持,只不过,AQS 里面的 state 在前者的实现中,一般小于等于一(除非重入锁),而后者的 state 则小于等于十,记录的是剩余可用临界资源数量。

所以,semaphore 天生就存在一个问题,如果某个线程重入了临界区,可用临界资源的数量是否需要减少?

停车场一共十个停车位,一辆车进去并占有了一个停车位,过了一段时间,这个向管理员报告,我还要占用一个停车位,先不管他占两个干啥,此时的管理员会同意吗?

实际上,在 Java 这个管理员看来,已经进入临界区的线程是「老爷」,提出的要求都会优先满足,即便他自身占有的资源并没有释放。

所以,在 Semaphore 机制里,一个线程进入临界区之后占用掉所有的临界资源都是可能的。

倒计时门栓 CountDownLatch

下面我们来看看这个 CountDownLatch,名字听起来挺高级,究竟提供了怎样的功能呢?

有这么一个常见的场景,我们一起来看看:

大家日常经常使用的拼多多,一件商品至少需要两到三人拼团,商家才会发货。

这里,我们不去研究它的商业模式,不管他是怎么实现盈利的,就这么一种场景,如果要用基本的并发 API 来实现,你可能会想到:

来一个线程阻塞一次,知道达到指定的数量后,全部唤醒

对,没错,CountDownLatch 内部就是这样实现的,轮子已经帮你造好了,我们来看看该怎么实现上述的模型案例:

多运行几次,你会发现结果不会错,拼团的人先后顺序可能不同,但商家一定是在三个人都准备好了之后才会发货。

除此之外,它还有更多的应用,比如百米赛跑,只有当所有运动员都准备好了之后,裁判员才会吹响哨子,等等等等。

实现原理也基本和显式锁类似,不同点依然在于对 state 的控制,CountDownLatch 只判断 state 是否等于零,不等于零就说明时机未到,阻塞当前线程。

而每一次的 countDown 方法调用都会减少一次倒计时资源,直至为零才唤醒阻塞的线程。

循环屏障 CyclicBarrier

CyclicBarrier 其实和 CountDownLatch 很像,我们先介绍完 CyclicBarrier,然后再和你一起去比较比较他俩的区别和相似点。

考虑这么一个场景:

公寓的班车总是在公寓楼下装满一车人之后,出发并开到地铁站,接着再回来接下一班人。

这么一个场景,我们考虑该怎么实现:

效果大概就是这个样子:

CyclicBarrier 就像一个屏障,实例化的时候需要传入两个参数,第一个参数指定我们的屏障最多拦截多少个线程后就打开屏障,第二个参数指明最后一个到达屏障的线程需要额外做的操作。

一般而言,最后一个线程到达屏障后,屏障将会打开,释放前面所有的线程,并在最后重新关上屏障。

CyclicBarrier 只需要用到一个 await 就可以完成所有的功能,我们总结下该方法的实现逻辑:

  1. 首先,减少一次可用资源数量

  2. 如果可用资源数为零,则说明自己是最后一个线程,于是会执行我们传入的额外操作,唤醒所有已经到达在等待的线程,并重新开启一个屏障计数。

  3. 否则说明自己不是最后一个线程,于是将自身线程在一个循环当中阻塞到一个条件队列上

好了,看完 CyclicBarrier 你会发现,它真的很类似我们的倒计时门栓,下面我们就来阐述他俩的区别与联系。

第一个区别

倒计时门栓 CountDownLatch 一旦被打开后就不能再次合上,也是说只要被调用了足够次数的 countDown,await 方法就会失效,它是一次性的。

CyclicBarrier 是循环发生的,当最后一个线程到达屏障,会优先重置屏障计数,屏障再次开启拦截阻隔。

第二个区别

CountDownLatch 是计数器, 线程来一个就记一个,此期间不阻塞线程,当达到指定数量之后才会去唤醒外部等待的线程,也就是说外部是有一个乃至多个线程等待一个条件满足之后才能继续执行,而这个条件就是满足一定数量的线程,这样才能激活当前外部线程的继续执行。

CyclicBarrier 像一个栅栏,来一个线程阻塞一个,直到阻塞了指定数量的线程后,一次性全部激活,让他们同时执行,像一个百米冲刺一样。

最后的最后

好了,以上就是我们 Java 并发包下面比较好用的三个工具类,其中前两个的底层实现几乎完全依赖显式锁的原理方法,后一个则是使用的显式锁加条件变量重新造的轮子,都是非常好用的工具!

除此之外还要说一点的是,整个并发这块内容,基本核心的东西我们都已经介绍完了,共计十四篇文章,从基本的线程概念,到锁原理,到线程池,再到异步任务,自认为总结的足够细致了,不知道你了解了多少呢?

记不住没关系,我也为你提供了一份思维导图的总结,罗列了上述基本的内容,你可以对照着进行回顾,同时也欢迎你私信我讨论探究。

三个好用的并发工具类相关推荐

  1. 第十章_多线程(2)_线程池原子性并发工具类

    目录 一.线程池 1 - 线程状态 2 - 线程池 3 - Executors线程池 二.Volatile 三.原子性 四.并发工具类 1 - 并发工具类-Hashtable 2 - 并发工具类-Co ...

  2. Java并发工具类(三)Exchanger

    Java并发工具类(三)Exchanger 在J.U.C并发包中提供了一些工具类,可以供我们在日常的开发中,根据不同的情况去进行一些相关的并发控制,具体的类有: CountDownLatch Sema ...

  3. JUC 常用 4 大并发工具类

    欢迎关注方志朋的博客,回复"666"获面试宝典 什么是JUC? JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些东西 该包的位置位 ...

  4. 死磕Java并发:J.U.C之并发工具类:Exchanger

    作者:chenssy 来源:Java技术驿站 前面三篇博客分别介绍了CyclicBarrier.CountDownLatch.Semaphore,现在介绍并发工具类中的最后一个Exchange.Exc ...

  5. 并发工具类(二)同步屏障CyclicBarrier

    前言   JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...

  6. 并发工具类:CountDownLatch、CyclicBarrier、Semaphore

    在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch ...

  7. j.u.c系列(11)---之并发工具类:Exchanger

    写在前面 前面三篇博客分别介绍了CyclicBarrier.CountDownLatch.Semaphore,现在介绍并发工具类中的最后一个Exchange.Exchange是最简单的也是最复杂的,简 ...

  8. 【重难点】【JUC 02】volitale 常用模式 、JUC 下有哪些内容 、并发工具类

    [重难点][JUC 02]volitale 常用模式 .JUC 下有哪些内容 .并发工具类 文章目录 [重难点][JUC 02]volitale 常用模式 .JUC 下有哪些内容 .并发工具类 一.v ...

  9. 线程池、volatile、原子性、并发工具类

    目录 线程状态 线程池-基本原理 线程池 - Executors默认线程池 线程池 - ThreadPoolExecutor 线程池参数-拒绝策略 volatile 原子性 原子性 - AtomicI ...

最新文章

  1. php安装问题_PHP安装十大经典问题
  2. linux命令history
  3. 聊聊并发-Java中的Copy-On-Write容器
  4. 1.1.1 数据结构的基本概念
  5. 优秀的java代码_像这样写,Java菜鸟也能写出牛逼的代码
  6. 作者:胡青青(1984-),女,就职于中国人民银行征信中心数据部
  7. JQuery------实现鼠标摁下抬起时div背景色改变
  8. Centos 云服务器磁盘占用率90%以上的排查解决
  9. SpringBoot+Mybatis+Druid批量更新 multi-statement not allow异常
  10. python爬虫免费代理池_Python爬取免费代理搭建代理池
  11. leetcode 刷题录
  12. Caltech-UCSD Birds 200 (CUB) 数据库预处理
  13. HTML5“爱心鱼”游戏总结
  14. 屏幕的单位如何计算机,如何查看您的计算机显示器有多少英寸
  15. 项目设计-基于SpringBoot和Vue开发的宿舍管理系统
  16. Neural Factorization Machines(NFM)
  17. Linux 的chmod权限数字777、755、644代表什么?
  18. 勇者斗恶龙———算法题
  19. 有N个灯放在一排,N个人进行操作,求灯泡最后的状态
  20. 均值与期望到底是不是一回事?

热门文章

  1. iphone桌面横屏设置在哪里_我和我各司其职的桌面们
  2. 2023届春招实习拉钩一面凉经
  3. 1017 The Best Peak Shape (35 分)(最佳峰形)(思路+详解+翻译+题意分析)Come brather!!!!!!!!!
  4. [mybatis]逆向工程MGB基本编写
  5. 哈工大威海计算机组成原理,哈工大威海计算机组成原理复习.pdf
  6. B-树、B+树、B*树详解
  7. MATLAB读取文件夹及其所有子文件夹内的图像
  8. lintcode 有效的括号序列
  9. CF755G PolandBall and Many Other Balls(多项式/倍增fft)
  10. Defuse the Bombs Gym - 102822D