1:Semaphore 基础
信号量:用来限制能同时访问共享资源的线程上限。
和锁不一样,锁只有一个共享资源;信号量的共享资源有多个,对访问的线程上限做限制。
作用:
可以做限流,只适合单机版,只限制线程数量,而不是限制资源数(tomcat 连接数)
可以作用于数据库连接池,享元模式下的,性能和可读性更好
2:创建信号量
Semaphore semaphore = new Semaphore(n);
// 传入 int 数字,表示共享资源的数目
public Semaphore(int permits) {
// 进入NonfairSync(permits) 方法
sync = new NonfairSync(permits);
}
进入NonfairSync(permits) 方法
NonfairSync(int permits) {
// 调用父类的 NonfairSync(permits) 方法
super(permits);
}
调用父类的 NonfairSync(permits) 方法
Sync(int permits) {
// 将传入进来的数值设置成 state 的值,作为共享变量
setState(permits);
}
3:获取信号量
调用 acquire()方法
public void acquire() throws InterruptedException {
// 进入 acquireSharedInterruptibly(1)方法
sync.acquireSharedInterruptibly(1);
}
进入 acquireSharedInterruptibly(1)方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
// 如果线程被打断,抛出异常
if (Thread.interrupted())
throw new InterruptedException();
// 进入 tryAcquireShared(1) 方法
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
进入 tryAcquireShared(1) 方法:
如果是公平锁,
protected int tryAcquireShared(int acquires) {
for (;;) {
// 如果等待队列中有线程,返回-1,非公平锁多了这一步的检查
if (hasQueuedPredecessors())
return -1;
// 获取 state 的数目
int available = getState();
// state -1
int remaining = available - acquires;
// 如果< 0 ,表示共享资源已经被使用完成;返回-1
// 如果 >0.cas 修改 state 的值,并返回
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
如果是非公平锁
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
回到 acquireSharedInterruptibly(1)方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquireShared(1) 返回剩余 state 的值, >=0 表示获取成功,线程继续向下运行
//如果 < 0,进入 doAcquireSharedInterruptibly(1)方法,加入等待队列
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
进入 doAcquireSharedInterruptibly(1)方法
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
// 如果是第一个进入等待队列的线程,会先创建一个亚元线程作为头节点;当前线程节点加入等待队列作为尾节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
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;
}
}
// shouldParkAfterFailedAcquire ():如果获取锁失败,则将前一个节点的 waitStatus 从 0 变成 -1
// parkAndCheckInterrupt() :使当前线程阻塞。如果当前线程被唤醒,会再次进入 for 循环竞争
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
3:释放信号量
调用 release() 方法
public void release() {
// 进入 releaseShared(1) 方法
sync.releaseShared(1);
}
进入 releaseShared(1) 方法
public final boolean releaseShared(int arg) {
// 进入 tryReleaseShared(1)方法
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
进入 tryReleaseShared(1)方法
protected final boolean tryReleaseShared(int releases) {
for (;;) {
// 进入循环,获取当前 state 的值
int current = getState();
// state 数值加 1
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
// cas 替换 state 的值,返回 true
if (compareAndSetState(current, next))
return true;
}
}
回到 releaseShared(1) 方法
public final boolean releaseShared(int arg) {
// tryReleaseShared(1)返回 true
if (tryReleaseShared(arg)) {
// 进入 doReleaseShared() 方法
doReleaseShared();
return true;
}
return false;
}
进入 doReleaseShared() 方法
private void doReleaseShared() {
for (;;) {
Node h = head;
// 判断等待队列是否为空,且有除头节点以外的其他节点
if (h != null && h != tail) {
int ws = h.waitStatus;
// 判断头结点的 waitStatus 是否为 -1
if (ws == Node.SIGNAL) {
// cas 将头节点的 waitStatus 从 -1 变成 0
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
// 进入 unparkSuccessor(h) 方法
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
// 队列为空,且只有头节点,返回
if (h == head) // loop if head changed
break;
}
}
进入 unparkSuccessor(h) 方法
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
// 头节点的 waitStatus 已经变成 0,不满足这个判断
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 获取头节点的后一个节点
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 存在的话,被唤醒,在 doAcquireSharedInterruptibly() 方法的循环中继续尝试获取锁
if (s != null)
LockSupport.unpark(s.thread);
}