Semaphore 源码分析

Posted zhuxudong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Semaphore 源码分析相关的知识,希望对你有一定的参考价值。

Semaphore

Semaphore 是基于同步器实现的计数信号量。
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。
公平的信号量可以保证不会出现线程饥饿,而非公平的信号量可以提供更高的吞吐量。

创建实例

    private final Sync sync;

    /**
     *  信号量的同步器实现
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

        Sync(int permits) {
            // 写入许可数
            setState(permits);
        }

        final int getPermits() {
            // 获取可用许可数
            return getState();
        }

        /**
         *  非公平地获取 acquires 个许可
         * created by ZXD at 15 Dec 2018 T 11:43:17
         * @param acquires
         * @return
         */
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                // 读取可用许可数
                final int available = getState();
                // 计算剩余许可数
                final int remaining = available - acquires;
                /**
                 * 1)剩余许可数 < 0,则直接返回,不更新可用许可数
                 * 2)更新可用许可书
                 */
                if (remaining < 0 ||
                        compareAndSetState(available, remaining)) {
                    return remaining;
                }
            }
        }

        /**
         *  尝试释放 releases 个许可
         * created by ZXD at 15 Dec 2018 T 11:44:56
         * @param releases
         * @return
         */
        @Override
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                final int current = getState();
                // 计算可用许可数
                final int next = current + releases;
                if (next < current) {
                    throw new Error("Maximum permit count exceeded");
                }
                // 更新许可数
                if (compareAndSetState(current, next)) {
                    return true;
                }
            }
        }

        /**
         *  递减 reductions 个许可
         * created by ZXD at 15 Dec 2018 T 11:46:19
         * @param reductions
         */
        final void reducePermits(int reductions) {
            for (;;) {
                final int current = getState();
                final int next = current - reductions;
                if (next > current) {
                    throw new Error("Permit count underflow");
                }
                if (compareAndSetState(current, next)) {
                    return;
                }
            }
        }

        /**
         *  一次性获取全部许可
         * created by ZXD at 15 Dec 2018 T 11:46:41
         * @return
         */
        final int drainPermits() {
            for (;;) {
                // 读取当前许可数
                final int current = getState();
                // 如果不是 0,则将其置为 0
                if (current == 0 || compareAndSetState(current, 0)) {
                    // 返回读取到的许可数
                    return current;
                }
            }
        }
    }

    /**
     *  非公平版本
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

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

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

    /**
     *  公平版本
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

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

        @Override
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                // 如果已经有线程在阻塞等待获取许可,则不允许获取
                if (hasQueuedPredecessors()) {
                    return -1;
                }
                final int available = getState();
                final int remaining = available - acquires;
                if (remaining < 0 ||
                        compareAndSetState(available, remaining)) {
                    return remaining;
                }
            }
        }
    }

    /**
     *  创建一个持有 permits 个许可的非公平信号量
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    /**
     * 创建一个持有 permits 个许可的
     * true:公平信号量
     * false:公平信号量
     */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

获取许可

  • 尝试获取一个许可,如果无许可可用,则阻塞等待,支持中断
    /**
     *  尝试获取一个许可,如果无许可可用,则阻塞等待
     *  1)获取到一个许可
     *  2)线程被中断
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
  • 尝试获取 permits 个许可,如果无许可可用,则阻塞等待,支持中断
    /**
     *  尝试获取 permits 个许可,如果无许可可用,则阻塞等待
     *  1)获取到一个许可
     *  2)线程被中断
     */
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) {
            throw new IllegalArgumentException();
        }
        sync.acquireSharedInterruptibly(permits);
    }
  • 尝试获取一个许可,如果无许可可用,则阻塞等待,不支持线程中断
    /**
     *  尝试获取一个许可,如果无许可可用,则阻塞等待,不支持线程中断
     *  1)获取到一个许可
     */
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }
  • 尝试获取 permits 个许可,如果无许可可用,则阻塞等待,不支持中断
    /**
     *  尝试获取 permits 个许可,如果无许可可用,则阻塞等待,不支持中断
     *  1)获取到一个许可
     */
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) {
            throw new IllegalArgumentException();
        }
        sync.acquireShared(permits);
    }
  • 如果有许可可用,则一次性获取所有的许可,并返回许可数,否则返回 0
    /**
     *  如果有许可可用,则一次性获取所有的许可,并返回许可数,否则返回 0
     */
    public int drainPermits() {
        return sync.drainPermits();
    }

释放许可

  • 将一个许可归还给信号量
    /**
     *  将一个许可归还给信号量
     */
    public void release() {
        sync.releaseShared(1);
    }
  • 将 permits 个许可归还给信号量
    /**
     * 将 permits 个许可归还给信号量
     */
    public void release(int permits) {
        if (permits < 0) {
            throw new IllegalArgumentException();
        }
        sync.releaseShared(permits);
    }

以上是关于Semaphore 源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Semaphore源码分析

Semaphore源码分析

AQS源码探究_09 Semaphore源码分析

AQS源码探究_09 Semaphore源码分析

源码分析:Semaphore之信号量

Semaphore源码分析