还是像之前,关于Semaphore的使用方法,我就不介绍了,依然提供一个博客地址供大家了解。https://blog.csdn.net/zzy7075/article/details/52095773
平常的使用的话:
`
//permits是指允许进入的线程数量
Semaphore semaphore=new Semaphore(permits);
semaphore.acquire();//还有acquire(permits);区别在于acquire获取一个,acquire(permits)获取多个
semaphore.release();//还有release(permits);同理
1.那么还是从构造方法入手。
public Semaphore(int permits) {
//sync继承aqs,基本做的就是setState(permits)
sync = new NonfairSync(permits);
}
2.先从acquire()入手,感觉两个方法的实现应该一样。
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);
}
//先看tryAcquireShared(arg)这个方法。
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
//从这个死循环当中可以看出3中情况,
//(1)负数:导致走doAcquireSharedInterruptibly
//(2)0:成功获取许可,结束
//(3)正数:成功获取许可,结束
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
//那么就需要看一下(1)情况了。
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
/**
*大致讲一下流程:将node放入等待队列当中,当node是老二的时候,就可以尝试去获取了,
*其余时候,就应该阻塞了。
*/
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null;
// help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
2.看一下acquire(permits)
//好了,GG,一模一样了
public void acquire(int permits) throws InterruptedException {
if (permits < 0)
throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
3.release()方法。
//猜测一下:release就是将state+上许可数。但是有个疑问,是如何保证没有占用的,不能够release??
//这个地方应该有一定的疑问,毕竟占用的时候,并没有给线程进行标记,那么应该没有办法区别开吧。
//经过自己的验证,发现这一点上,确实有问题。但是你说是问题,也不算是问题。就有点懵
//那么就看一下release()方法
public void release() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
//之前分析过很多次了,就是唤醒阻塞的线程
doReleaseShared();
return true;
}
return false;
}
//始终返回true,做的事情就只是state+release的数量
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;
}
}
4.release(permits)
//完
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}