Java并发|Semaphore如何实现限流器

大家好,我是七哥,今天是2020.10.24,也是我们程序员的节日,在这里祝大家节日快乐。

絮叨一下

今天我们一起来学习下如何使用JDK提供的并发工具类来实现限流。在之前的工作中,我们有一个限流的场景,那就是在调用关联方系统的时候需要限流,因为提供服务方是保险的核心系统,大家应该都懂这种系统支持的并发不会大,为了保护双方系统的可用性,作为调用方我们在调用的时候也会做一个限流控制。这种场景在工作中很常见,之前面试的时候也经常会被问到:「Java并发包你有哪些使用场景?」

你可能已经想到了,我们当时的解决方案就是使用信号量 Semaphore, 由于是JDK并发包中提供的工具类,也不用引入第三方包,实现非常的简单。这里要注意的是,我们当时的服务是分布式集群部署,而 信号量只能保存单机的并发控制,也就是必须在一个JVM进程中,所以我们是用服务提供方支持的最大并发数除以我们的机器数量来为每台实例配置限流的。

信号量简介

信号量在《Java并发编程的艺术》一书中是这样定义的:

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。

看了上面的描述对于信号量的定义其实还是不好理解,我来举个例子帮助大家记忆,起码我是这样记住的。

我们可以将信号量理解为信号灯,也就是我们生活中的红绿灯,假设早晚高峰主干道需要限流,同一时间只允许10辆车在当前道路上行驶,那么其他车辆都必须在路口等待,所以前10辆车看到的就是绿灯可以通行,后面的车看到的就是红灯不能驶入此道路,但是如果有2辆车已经驶出这条道路,那么后面的车辆中就又可以允许两辆车驶入。

在这个例子中,车辆就是线程,驶入马路就是表示线程执行,离开马路就是线程执行完成,看见红灯就是表示线程阻塞,不能执行。

这个举例是不是很形象呢? 反正我就是这样记住信号量的语义的。

下面我们首先介绍信号量模型,之后介绍如何使用信号量以及使用场景,最后我们再用信号量来实现一个限流器。

同时如果看到这里你依然感兴趣,那么请你带着这样一个问题往下看。

通过上面的讲解你觉得 Semaphore 和 Lock 有什么区别呢?既然有 Java SDK 里面提供了 Lock,为啥还要提供一个 Semaphore ?

如果你不能回答这个问题,那么往下看,看完你要是还不知道,我就不用说啥了。

信号量模型

信号量模型还是很简单的,可以简单概括为:一个计数器,一个等待队列,三个方法。在信号量模型里,计数器和等待队列对外是透明的,所以只能通过信号量模型提供的三个方法来访问它们,这三个方法分别是:init()、down() 和 up()。你可以结合下图来形象化地理解。

在Java SDK 中,信号量模型的实现就是由我们的 java.util.concurrent.Semaphore 实现的,而上面的三个方法都是原子的, Semaphore 类能够保证这三个方法的原子操作。

  • init() 方法,即初始化计数器的值,对应的就是Semaphore的构造器方法。
  • down() :计算器的值减一,如果此时计数器的值「小于0」,则当前线程被阻塞,也就是上面例子中允许同行的车辆已满,否则可以继续执行。
  • up()方法:计数器的值加1;如果此时计数器的值「小于或者等于0」,则唤醒队列中的一个线程,并将其从阻塞队列中移除。

上面的方法如果你觉得不好理解,那么可以看下 JDK 中的具体实现 Semaphore 中提供的方法。

信号量应用场景

  • Semaphore可以用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有10个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,就可以使用Semaphore来做流量控制。

  • 用于限制接口调用大并发量,保护系统可用性,这也是一开始我说的我们之前的用法;

  • Semaphore 也是可以用来实现互斥锁的;原理很简单,就是在进入进阶区代码前我们使用 acquire() 操作,执行完退出临界区代码之前执行一下 release() 操作。特殊的点就再于,我们初始化时生命计数器为1即可。

如果上面的代码没看懂,那么你就要问下自己应该不适合做程序员。

这里是条分割线 。。

解释下上面代码的执行流程,信号量是如何保证互斥的。

假设两个线程 T1 和 T2 同时访问 addOne() 方法,当它们同时调用 acquire() 的时候,由于 acquire() 是一个原子操作,所以只能有一个线程(假设 T1)把信号量里的计数器减为 0,另外一个线程(T2)则是将计数器减为 -1。对于线程 T1,信号量里面的计数器的值是 0,大于等于 0,所以线程 T1 会继续执行;对于线程 T2,信号量里面的计数器的值是 -1,小于 0,按照信号量模型里对 down() 操作的描述,线程 T2 将被阻塞。所以此时只有线程 T1 会进入临界区执行count+=1;。

当线程 T1 执行 release() 操作,也就是 up() 操作的时候,信号量里计数器的值是 -1,加 1 之后的值是 0,小于等于 0,按照信号量模型里对 up() 操作的描述,此时等待队列中的 T2 将会被唤醒。于是 T2 在 T1 执行完临界区代码之后才获得了进入临界区执行的机会,从而保证了互斥性。

限流器的实现

开头我说了,我们在工作中是用Semaphore来实现接口调用时的限流的,那么如何实现呢?

在代码中,虽然有30个线程在执行,但是只允许10个并发执行。Semaphore的构造方法Semaphore(int permits)接受一个整型的数字,表示可用的许可证数量。Semaphore(10)表示允许10个线程获取许可证,也就是最大并发数是10。Semaphore的用法也很简单,首先线程使用Semaphore的acquire()方法获取一个许可证,使用完之后调用release()方法归还许可证。

简言之,使用信号量,我们可以轻松地实现一个限流器,使用起来还是非常简单的。

接下来要做的就是去寻找工作中合适的业务场景接入了,掌握了这个面试Java并发你也能扯一扯了。

看完文章的你在 Java并发编程 这块又掌握了一个常用的知识点,恭喜你。

前面问了一个问题,「Semaphore和Lock之间的区别是什么呢?」

这里总结下:

  • 共同点:Semaphore也可以实现互斥锁的功能;
  • 区别:Semaphore 还有一个功能是 Lock 不容易实现的,那就是:「Semaphore 可以允许多个线程访问一个临界区。」

原创不易,希望你能帮我个小忙呗,如果本文内容你觉得有所收获,请帮忙点个“在看”,或者转发分享让更多的小伙伴看到。


 Java并发|Atomic包下的原子操作类

 我是如何从电脑小白走上编程之路

 volatile关键字你不了解?赶紧来看看



©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351