欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Java 信号量Semaphore

程序员文章站 2022-06-15 13:25:50
semaphore也是一个同步器,和前面两篇说的countdownlatch和cyclicbarrier不同,这是递增的,初始化的时候可以指定一个值,但是不需要知道需要同步的线程个数,只需要在同步的地...

  semaphore也是一个同步器,和前面两篇说的countdownlatch和cyclicbarrier不同,这是递增的,初始化的时候可以指定一个值,但是不需要知道需要同步的线程个数,只需要在同步的地方调用acquire方法时指定需要同步的线程个数;

一.简单使用

  同步两个子线程,只有其中两个子线程执行完毕,主线程才会执行:

详解Java 信号量Semaphore

这个信号量也可以复用,类似cyclicbarrier:

详解Java 信号量Semaphore

二.信号量原理 

  看看下面这个图,可以知道信号量semaphore还是根据aqs实现的,内部有个sync工具类操作aqs,还分为公平策略和非公平策略;

详解Java 信号量Semaphore

构造器:

acquire(int permits)方法:

再看看release(int permits)方法:

  以最上面的例子简单说一下,其实不是很难,首先线程1和线程2分别去调用release方法,这个方法里面会将aqs中的state加一,但是在执行这个操作之前,主线程肯定会先到acquire(2),在这个方法里面,假如默认使用非公平策略,首先获取当前的信号量state(state的初始值是0),用当前信号量减去2,如果小于0,那么当前主线程就会丢到aqs队列中阻塞;

  这个时候线程1的release方法执行了,于是就把信号量state加一(此时state==1),cas更新state为一,成功的话,就调用doreleaseshared()方法唤醒aqs阻塞队列中最先挂起的线程(这里就是因为调用acquire方法而阻塞的主线程),主线程唤醒之后又会去获取最新的信号量,与2比较,发现还是小于0,于是又会阻塞;

  线程2此时的release方法执行完成,重复线程一的操作,主线程唤醒之后(此时state==2),又去获取最新的信号量发现是2,减去acquire方法的参数2等于0,于是就用cas更新state的值,然后acquire方法也就执行完毕,主线程继续执行后面的代码;

  其实信号量还是很有意思的,记得在项目里,有人利用信号量实现了一个故障隔离,什么时候我可以把整理之后的代码贴出来分享一下,还是很有意思的,就跟springcloud的熔断机制差不多,场景是:比如你在service的一个方法调用第三方的接口,你不知道调不调得通,而且你不希望每次前端过来都会去调用,比如当调用失败的次数超过100次,那么五分钟之后才会再去实际调用这个第三方服务!这五分钟内前调用这个服务,就会触发我们这个故障隔离的机制,向前端返回一个特定的错误码和错误信息!

以上就是详解java 信号量semaphore的详细内容,更多关于java 信号量semaphore的资料请关注其它相关文章!