AQS在Semaphore的应用:
在Semaphore中,State表示许可证的数量
看tryAcquire方法,判断nonfairTryAcquireShared大于等于0的话,代表获取锁成功;
tryAcquire方法具体实现:
这里会先检查剩余许可证数量够不够这次需要的,用减法来计算,如果直接不够,那就返回负数,表示失败,如果够了,就用自旋加CompareAndSetState来改变state状态,改变成功就返回正数;或者是期间如果被其他人修改了导致剩余数量不够,那也返回负数代表获取失败;获取失败的陷入阻塞状态
对于共享变量,对其进行修改时多线程环境下需要使用原子操作:
与CountDownLatch区别:
1.获取时,CountDownLatch获取根据构造函数的count,只要count>0就会阻塞,Semaphore获取permits,只要permits>=0获取更新permits成功就不会阻塞,只有当permits==0才会阻塞
2.释放时,CountDownLatch,初始状态为0不去阻塞当然也不会去释放,每次循环遍历减1,并去判断原子更新后的值是否等于0,如果等于0,就返回true就释放,Semaphore当前剩余的个数加上需要释放的个数只要大于当前剩余的个数并且更新成功就可以释放,能释放一个是一个。
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
// 原子更新成功 直接返回剩余许可证个数 大于0不进入阻塞,当剩余个数小于0才阻塞
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
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;
}
}