前言
Semaphore一种通常用于维持数量的信号量工具,在Java 并发中最常见的使用就是维持并发线程的个数,正如之前提到的,并不是并发场景线程越多越好,应该是跟对应的业务场景及CPU数量共同决定。而需要维持数量时,我们大致就需要一个JUC里面Semaphore这样一个信号量工具。Semaphore 同样依赖于AQS实现(shared),内部持有一个Sync对象,同样存在公平实现、非公平实现两种模式(可以在构造时指定fair参数)。
原理
每次线程执行前夕都会从这里默认通过一下许可,然后执行完毕时释放一下许可,根据维系的数量来决定当前线程是该等待还是执行。
简单看一下源码,实现蛮简单的
首先是持有AQS对象
public class Semaphore implements java.io.Serializable {
private static final long serialVersionUID = -3222578661600680210L;
/** All mechanics via AbstractQueuedSynchronizer subclass */
private final Sync sync;
取许可及释放操作
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
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;
}
}
公平非公平两种实现版本:
/**
* NonFair version
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
/**
* Fair version
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
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;
}
}
}
网友评论