【java并发】Semaphore源码解析

一、概述

Semaphore信号量,主要功能是限制能够运行的线程量,指定固定数量的许可,只有获取许可的线程可以运行,若没有许可获取则阻塞,直到获取许可。

二、源码分析

1、构造函数

    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and nonfair fairness setting.
     *	创建给定许可证数量信号量和非公平设置
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     * 初始许可证数量.
     * 这个值允许为负数,在这种情况下必须在任何获取之前释放
     */
	public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
    /**
    * @param fair {@code true} 保证竞争先进先出
    */
	public Semaphore(int permits, boolean fair) {
	        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

Semaphore中同步器Sync继承AQS实现AQS中的共享模式tryReleaseShared(int releases)方法,同步器只实现了共享锁的释放,并未实现锁的获取tryAcquireShared(int arg)方法;
Semaphore中公平和非公平是通过它的两个私有的静态内部类FairSync、NonFairSync实现,他们通过继承Sync并实现共享锁的获取tryAcquireShared(int arg)方法;
非公平实现:

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }
		// 只是实现了AQS中的共享锁的获取
        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);
        }
		// 只是实现了AQS中的共享锁的获取
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }

2、void acquire()

这个方法是从信号量获取一个许可,在获取到许可,或线程中断之前,当前线程阻塞;获取许可后立即返回并将许可数减一

	/**
	* 如果没有许可可用,则会休眠知道发生以下两种情况
	* 1、其他调用release方法释放许可,并且当前线程获取到许可
	* 2、其他线程中断了当前线程
	* 	1)当前线程在进入这个方法时设置了中断标志位
	* 	2)等待许可时发生了中断,则抛出中断异常
	*/
 	public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

这个方法是直接调用AQS的acquireSharedInterruptibly(int ard)方法;
方法实现原理请查看AQS源码:

	/**
	* 首先检测是否中断.中断后抛出异常
	* 尝试获取许可,成功退出;失败则进入AQS队列,直至成功获取或中断
	*/
	public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        // 尝试获取锁,返回剩余共享锁的数量;小于0则加入同步队列,自旋
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

tryAcquireShared(arg)则会调用Semaphore中两个同步器的实现方法;
如果获取失败则加入队列等待唤醒;

非公平模式的实现

非公平实现都是首先查看是否有可获取的许可,如果有则获取成功,没有则进队列等待;利用此可以提高并发量,但可能导致某些线程长时间获取不到许可,造成线程‘饿死’。

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

直接调用其父类Sync中非公平共享获取

	final int nonfairTryAcquireShared(int acquires) {
		// 自旋直到无许可或者状态位赋值成功
        for (;;) {
            int available = getState();
            int remaining = available - acquires;
            // 如果小于0则直接返回,否则利用CAS给AQS状态位赋值
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
公平模式的实现

公平与非公平的区别在于始终按照AQS队列FIFO的顺序来的

protected int tryAcquireShared(int acquires) {
	//自旋 CAS 实现线程安全
    for (;;) {
    	// 判断是否有前置任务排队
        if (hasQueuedPredecessors())
            return -1;
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

以上两种模式获取失败后都会调用doAcquireSharedInterruptibly(int arg);自旋等待获取锁 。源码解析请看AQS解析

3、void release()

公平和非公平使用相同的释放
释放许可

    public void release() {
        sync.releaseShared(1);
    }

调用AQS中的releaseShared(int arg)

    public final boolean releaseShared(int arg) {
    	// 调用Sync实现的tryReleaseShared
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

tryReleaseShared(int arg)是父类Sync实现。自旋直到释放成功

        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;
            }
        }

如果释放许可成功,则调用AQS中的doReleaseShared()方法来唤醒AQS队列中等待的线程
源码解析请看AQS解析

这里就是Semaphore的主要源码。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章