前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Semaphore源码解析

Semaphore源码解析

作者头像
写一点笔记
发布2020-08-25 14:25:51
5620
发布2020-08-25 14:25:51
举报
文章被收录于专栏:程序员备忘录程序员备忘录

Semaphore(信号量)是控制访问线程的基于AQS的并发工具。也就是说使用Semaphore能够控制访问资源的并发量。比如在限流这块。

按照限流的逻辑,所以在使用的时候,需要进行设置最大的并发线程,按照我们之前对countDloadLatch的理解。通过设定总量,然后在条件满足之后进行下一工作。

semaphore则是通过设定最大的并发线程,在当前线程消耗的指定的掉总量之后。总量的剩余量与当初设定的总量进行对比,如果小于总量就排队,如果大于总量就进行阻塞。如果超过超时时间就剔除。

semaphore的大致逻辑就是这样。其中使用了AQS做基础的保证。

代码语言:javascript
复制
public class MySemaphore {


    public static Semaphore semaphore=new Semaphore(2);


    static class task implements Runnable{




        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                semaphore.release();
            }
        }
    }




    public static void main(String[] args) {
        ExecutorService executorService= Executors.newCachedThreadPool();
        for (int i=0;i<10;i++){
            executorService.submit(new task());
        }
        executorService.shutdown();


    }
}

我们可以修改Semaphore的值,然后观察结果,能够很明显的观察到这种并发控制的效果。

下面我们从源码角度看一下他是如何实现的。

从图中可以看出,Seamaphore的结构和其他的并发工具一样,都有公平锁和非公平锁,一版这种情况都是和AQS关系很大,然后看到很多之前我们看到的方法。

下面我们从初始化方法和上述demo的层面上进行深入。

代码语言:javascript
复制
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

在初始化的时候,默认采用的是非公平锁。

代码语言:javascript
复制
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

或者自行决定是公平还是非公平锁

代码语言:javascript
复制
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

当我们调用acquire()方法的时候,发现调用的是acquireSharedInterruptibly,我们跟踪一下。

doAcquireShared这个方法我们之前分析过,就是要从AQS链表中从后向前的寻找。剔除超时的,把能激活的线程向前移动,然后等待之前的额线程执行完毕之后抢夺head节点。

那么这块的意思就是说要先获取state的数量,然后看state减去申请的数量(这里是1),是否还有剩余,如果有剩余说明可以加入到队列。如果state没有剩余,那么就进行自旋,然后一直尝试往链表中添加。

按照这种逻辑,那么释放的时候,就应该是是对state的值进行相加。那么我们看看源码是如何实现的。

代码语言:javascript
复制
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

果然,Semaphore就是对state的值进行加法操作。这样保证信号量的值的统一。

好了关于Semaphore的源码解析就到这里了。

总结:

Semaphore使用AQS进行信号量的实现。通过对state值得维护来实现信号量模式,在实际应用中,我们可以采用Semaphore来做系统的限流业务。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员备忘录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档