三个好用的并发工具类

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

以前的文章中,我们介绍了太多的底层原理技术以及新概念,本篇我们轻松点,了解下 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 并发包下面比较好用的三个工具类,其中前两个的底层实现几乎完全依赖显式锁的原理方法,后一个则是使用的显式锁加条件变量重新造的轮子,都是非常好用的工具!

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Error Handling in ASP.NET Core

前言 在程序中,经常需要处理比如 404,500 ,502等错误,如果直接返回错误的调用堆栈的具体信息,显然大部分的用户看到是一脸懵逼的,你应该需要给用户返回那些看得懂的界面。比如,“当前页面不存在…

基于python的selenium

一.安装 安装WebDriver 查看chrome版本号,设置-帮助-关于Google chrome,找到版本号。 可以到这个网站进行下载对应版本的chromedriver,如果chrome浏览器版本过高,可以下载最新版的chromedriver进行使用 Chrome for Testing availability 下载下来之后…

多信息登录、检测用户信息是否完善且引导补全

大家好,我是雄雄,欢迎关注:穆雄雄的博客 前言 现在是2022年4月28日13:41:29! 今天分享两块内容。 1.需求:用户可以通过手机号、邮箱来注册我们的系统,用户完成之后,可以去完善自己的个人信息…

PNG 图片压缩原理解析

转载自 PNG 图片压缩原理解析 什么是PNG PNG的全称叫便携式网络图型(Portable Network Graphics)是目前最流行的网络传输和展示的图片格式,原因有如下几点: 无损压缩:PNG图片采取了基于LZ77派生算法对文件进行压缩&…

element ui实现多层级复杂表单的操作(添加与回显)之表单操作交互操作

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 前言 现在是2022年5月3日11:47:15!劳动节假期已经过去了三天了,今天是被封家里的第7天,也是解封的第一天。 说实话,在家里的工作效率一点都…

TypeScript 2.5 发布,增加语言级重构

在 TypeScript 2.5 版本中,Microsoft 专注于提高开发人员的生产力,其范围已经超出了代码编辑器所提供的常见功能。 习惯于类型语言(如 C#)的开发人员喜欢使用那些可以轻松执行常见重构的工具。现在 TypeScript 可以利…

element ui实现多层级复杂表单的操作(添加与回显)之添加功能实现

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 前言 现在是2022年5月3日13:35:15!文接上篇。[element ui实现多层级复杂表单的操作(添加与回显)之表单操作交互操作](element ui实现多层级复杂表单的操…

Entity Framework Core Like 查询揭秘

在Entity Framework Core 2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在 LINQ 查询中直接调用。 不过Entity Framework 中默认提供了StartsWith、Contains和EndsWith方法用于解决模糊查询,那…

element ui实现多层级复杂表单的操作(添加与回显)之回显功能实现

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 前言 现在是2022年5月3日17:02:30!文接上两篇。 [element ui实现多层级复杂表单的操作(添加与回显)之表单操作交互操作](element ui实现多层级复杂表单…

在Mac的Docker中运行DotNetCore2.0

最近学习Angular4,服务端准备使用DotNetCore API来实现,本文简单介绍下在Mac中怎样将DotNetCore程序部署在Docker中,并使用Nginx做反向代理让程序可以跑起来。 具体步骤如下 安装Docker拉取DotNetCore镜像使用VS For Mac创建DotNetCore应用…

springboot实现复杂业务下的更新操作

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 前言 现在是2022年5月4日19:25:55!今天写了个这样的功能: 某用户在一天内有多个训练项目,比如:晨跑,有氧训练,跳绳这…

elementui解决el-dialog不清空内容的问题,el-dialog关闭时销毁子组件

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 前言 现在是2022年5月5日22:48:21! 今天在使用element-ui中的el-dialog的时候遇到了个这样的问题:页面上点击添加的按钮,弹出el-dialog对话框&#xff…

MySQL 中的重做日志,回滚日志以及二进制日志的简单总结

转载自 MySQL 中的重做日志,回滚日志以及二进制日志的简单总结 MySQL中有六种日志文件,分别是:重做日志(redo log)、回滚日志(undo log)、二进制日志(binlog)、错误日志…

c语言分离三位数

#include<stdio.h> main(){ int k,l,m,n;printf("请输入一个三位数"); scanf("%d",&k);lk/100;mk/10%10;nk%10;printf("这个三位数的百位是:%d\n",l);printf("这个三位数的十位是:%d\n",m);printf("这个三位数的个位是…

分布式ID自增算法 Snowflake

近在尝试EF的多数据库移植&#xff0c;但是原始项目中主键用的Sqlserver的GUID。MySQL没法移植了。 其实发现GUID也没法保证数据的递增性&#xff0c;又不太想使用int递增主键&#xff0c;就开始探索别的ID形式。 后来发现twitter的Snowflake算法。 一开始我尝试过直接引用N…

java中,根据指定日期显示出前n天的日期

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 今天分享的是&#xff1a;在java中&#xff0c;根据指定日期显示出前n天的日期 效果如下&#xff1a; 大家注意观察上面的时间&#xff0c;我传入的时间是&#xff1a;2022年5月9日21:28:…

jdbc实现批量给多个表中更新数据(解析Excel表数据插入到数据库中)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年5月19日08:01:51 今天遇到了个这样的需求&#xff0c;解析excel表中的数据&#xff0c;以JDBC的方式&#xff0c;将数据批量更新至不同的数据表中。注意&am…

.Net Core 全局配置读取管理方法 ConfigurationManager

最近在学习.Net Core的过程中&#xff0c;发现.Net Framework中常用的ConfigurationManager在Core中竟然被干掉了。 也能理解。Core中使用的配置文件全是Json&#xff0c;不像Framework使用的XML&#xff0c;暂时不支持也是能理解的&#xff0c;但是毕竟全局配置文件这种东西还…

Http 持久连接与 HttpClient 连接池

转载自 Http 持久连接与 HttpClient 连接池 一、背景 HTTP协议是无状态的协议&#xff0c;即每一次请求都是互相独立的。因此它的最初实现是&#xff0c;每一个http请求都会打开一个tcp socket连接&#xff0c;当交互完毕后会关闭这个连接。 HTTP协议是全双工的协议&#x…

jdbc解析excel文件,批量插入数据至库中

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年5月20日09:32:38今天遇到了个这样的需求&#xff0c;解析excel表中的数据&#xff0c;以JDBC的方式&#xff0c;将数据批量更新至不同的数据表中。注意&…