Semaphore简介:
线程上的信号量机制。
通过 acquire() 获取一个许可,没有便阻塞等待,release() 释放一个许可。
原理:实现又是基于AQS的共享锁。并且支持公平和非公平
其实就是初始化了一个AQS上的state,每次acquire就是去state上尝试减一,每次release就是去state上加一,
内部类及构造器:
维护了三个内部类。经典的aqs写法
公平和非公平两种都有对应的实现
构造器:
//非公平
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
//可以指定是否公平
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
NonfairSync(int permits) {
super(permits);
}
Sync(int permits) {
setState(permits);
}
//最后是来到AQS当中来设置state来了
protected final void setState(int newState) {
state = newState;
}
重要方法:
获取许可:
//调用的是aqs共享锁中的可打断方法
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//一次甚至可以去多获取几个许可
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
//该方法来自于AQS,使用的tryAcquireShared需要我们重写
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//如果acquire没有了许可,获取不到才会阻塞,具体要看aqs源码
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
//再次回归aqs的使用,只需重写tryacquireshared
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
//继续调用Sync中实现的方法,可以看出,尝试获取许可的过程实际上就是去尝试在state上减的过程
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
以上就是去或区域许可的流程,如果不够就会陷入阻塞。直到获取到。
当然了,Semaphore是支持可否打断的,上面是可以打断的,当然还有不能打断的
//在Semaphore里都差不多。但具体可打断原理仍然要看AQS
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
public void acquireUninterruptibly(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);
}
还有可以尝试获取,获取不到无所谓不会阻塞的实现:
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
public boolean tryAcquire(int permits) {
if (permits < 0) throw new IllegalArgumentException();
return sync.nonfairTryAcquireShared(permits) >= 0;
}
//下面两个方法可以去指定尝试时间,都是基于AQS
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
下面就看释放许可
释放许可
public void release() {
sync.releaseShared(1);
}
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
//AQS中的方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
//就是一个通过CAS去释放许可,也就是去加state的过程
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强大无比