JAVA并发包(二十五):Semaphore

Semaphore也是高并发中控制并发量的工具,它维护一系列的运行许可。每个线程运行之前来获取许可,许可的数量有限,只有获得的线程才能继续运行,否则阻塞等待。

通过前面对CountDownLatch的学习,现在来理解Semaphore应该会轻松点。

一、基本代码结构

public class Semaphore implements java.io.Serializable {
    /** Semaphore的核心逻辑在Sync */
    private final Sync sync;

    /** Sync继承于AQS */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        Sync(int permits) {
            setState(permits);
        }

        final int getPermits() {
            return getState();
        }
	}

	/** 构造器默认使用非公平模式 */
	public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    /** 指定是否使用公平模式 */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
}    

二、获取许可

获取许可的方法是acquire()

	public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
 
 	public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        /** 如果返回小于0,那么调用doAcquireSharedInterruptibly(arg)方法,阻塞线程等待,
        另外tryAcquireShared有公平和非公平之分,后面代码分析 */
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
     
   		/** 非公平模式获取许可 */  
		protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
        
        /** 非公平获取许可,直接用CAS竞争 */
		final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

		/** 公平模式获取许可,如果等待队列中有线程等待获取许可,那么返回-1,线程会被阻塞放到等待队列 */
		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;
            }
        }

三、释放许可

使用Semaphore使用完许可之后必须释放许可,否则后面的线程将会得不到许可而不能运行。释放许可的方法是release(),我们下面分析

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

	public final boolean releaseShared(int arg) {
		// tryReleaseShared(arg)方法在Semaphore类中实现,我们后面讲解
        if (tryReleaseShared(arg)) {
        	// doReleaseShared()方法是AQS的方法,主要是唤醒等待线程去获取许可
            doReleaseShared();
            return true;
        }
        return false;
    }

	/** 释放许可,代码逻辑是CAS相加释放的许可数量 */
	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的几个结论:

  1. 使用许可的数量控制并发数量,内部使用AQS维护等待许可的线程,使用CAS竞争获取许可。
  2. 公平非公平之分:公平模式的Semaphore可以让等待许可的线程先到先得。
  3. 有借有还。许可使用完之后必须归还。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值