Semaphore用例、源码分析讲解

时间:2020-06-10
本文章向大家介绍Semaphore用例、源码分析讲解,主要包括Semaphore用例、源码分析讲解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
semaphore 也就是我们常说的信号灯,semaphore 可以控制同时访问的线程个数,通过 acquire 获取一个许可,如果没有就等待,通过 release 释放一个许可。有点类似限流的作用。叫信号灯的原因也和他的用处有关,比如某商场就 5 个停车位,每个停车位只能停一辆车,如果这个时候来了 10 辆车,必须要等前面有空的车位才能进入。
使用案例
public static void main(String[] args) {
            Semaphore semaphore=new Semaphore(5);
            for(int i=0;i<10;i++){
                new Car(i,semaphore).start();
            }
        }
        static class Car extends Thread{
            private int num;
            private Semaphore semaphore;
            public Car(int num, Semaphore
                    semaphore) {
                this.num = num;
                this.semaphore = semaphore;
            }
            public void run(){
                try {
                    semaphore.acquire();//获取一个许可
                    System.out.println("第"+num+"占用一个停车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println("第"+num+"俩车走喽");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
使用场景
Semaphore 比较常见的就是用来做限流操作了。
Semaphore 源码分析
从 Semaphore 的功能来看,我们基本能猜测到它的底层实现一定是基于 AQS 的共享所,因为需要实现多个线程共享一个领排池创建 Semaphore 实例的时候,需要一个参数 permits,这个基本上可以确定是设置给 AQS 的 state 的,然后每个线程调用 acquire 的时候,行 state = state - 1,release 的时候执行 state = state + 1,当然,acquire 的时候,如果 state = 0,说明没有资源了,需要等待其他线程 release。
Semaphore 分公平策略和非公平策略
FairSync:
static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            for (; ; ) { // 区别就在于是不是会先判断是否有线程在排队,然后才进行 CAS 减操作
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 || compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

NofairSync :

通过对比发现公平和非公平的区别就在于是否多了一个hasQueuedPredecessors 的判断。
static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

    final int nonfairTryAcquireShared(int acquires) {
        for (; ; ) {
            int available = getState();
            int remaining = available -
                    acquires;
            if (remaining < 0 || compareAndSetState(available, remaining))
                return remaining;
        }
    }
由于后面的代码和 CountDownLatch 的是完全一样,都是基于共享锁的实现,所以也就没必要再花时间来分析了。
至此,Semaphore 讲解就结束了,希望朋友们能领悟一些知识。

原文地址:https://www.cnblogs.com/47Gamer/p/13083667.html