Semaphore信号量及源码解析
Semaphore 通常用于限制可以访问某些资源的线程数目。
Semaphore使用
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
int j = i;
new Thread(() -> {
log.debug("-->线程{}启动", j + "");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(" -->线程{}停止", j + "");
}).start();
}
}
发现10个线程基本上是同时开始同时结束,如果只想同时最多3个线程执行访问,那么就可以Semaphore来进行限制
public static void main(String[] args) {
// 设置型号量为3
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 10; i++) {
int j = i;
new Thread(() -> {
try {
semaphore.acquire();
log.debug("-->线程{}启动", j + "");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug(" -->线程{}停止", j + "");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
}
}
发现同时只有3个线程访问了
Semaphore源码
Semaphore构造
// Semaphore构造默认是生成一个非公平的同步器
public Semaphore(int permits) {
// 把初始值传给同步器(非公平)
sync = new NonfairSync(permits);
}
/**
* 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);
}
}
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
// 最终把初始值赋值给了AQS State
Sync(int permits) {
setState(permits);
}
final int getPermits() {
return getState();
}
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;
}
}
final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current) // underflow
throw new Error("Permit count underflow");
if (compareAndSetState(current, next))
return;
}
}
final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}
发现最终把传入的3赋值给了AQS的state
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
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
nonfairTryAcquireShared
final int nonfairTryAcquireShared(int acquires) {
// 死循环
for (;;) {
// 我们构造传入的状态Semaphore semaphore = new Semaphore(3);
// 那么available 就等于 3
int available = getState();
// acquires是我们传入的1 那么remaining 就是2
int remaining = available - acquires;
/* 如果remaining 为负就会返回remaining
* 如果不为负就会CAS操作把之前的state由3改为2
* 那么下一个才线程来 int available = getState();
* available就是2以此类推下一个线程available就是1
* 下下个线程就是0,那么第四个线程
* int remaining = 0 - 1;那么这是remaining就是负数
* 负数表示失败 正数表示成功
*/
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
回到acquireSharedInterruptibly方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
/*
* 刚刚看了上面tryAcquireShared里面调用的
* nonfairTryAcquireShared方法 如果我么设置只能3个同时访问
* 第四个线程则会返回负数的情况,如果是负数则会调用doAcquireSharedInterruptibly
*/
doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
// 添加一个node节点方便线程等待和他关联
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
// 死循环
for (;;) {
// 获取他的前任节点p
final Node p = node.predecessor();
// 如果p是头节点 说明他是第一个(因为第一个节点是占位节点)
if (p == head) {
// 再去尝试一次获取锁
int r = tryAcquireShared(arg);
// 如果r>=0 说明获取到了锁
if (r >= 0) {
// 设置当前节点为头节点
setHeadAndPropagate(node, r);
// 把之前的头结点从链表中断开
p.next = null; // help GC
failed = false;
return;
}
}
// 设置前驱节点的状态为-1(因为-1表示有唤醒后面节点的职责)
if (shouldParkAfterFailedAcquire(p, node) &&
// 线程阻塞 parkAndCheckInterrupt里会判断当前线程是否被打断过
parkAndCheckInterrupt())
// 如果打断了就抛异常进行打断
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
parkAndCheckInterrupt
private final boolean parkAndCheckInterrupt() {
// 阻塞主自己
LockSupport.park(this);
// 返回是否被打断过
return Thread.interrupted();
}
release()
public void release() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
// 尝试空一个位置出来给其他线程执行
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
protected final boolean tryReleaseShared(int releases) {
for (;;) {
// 获取状态如果3个线程都还是运行,每一个线程把状态-1那么线程状态就是0
int current = getState();
// 加1,表示空一个位置出来
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
// cas尝试把State0改成1
if (compareAndSetState(current, next))
return true;
}
}
回到releaseShared方法这时tryReleaseShared方法返回true开始执行 doReleaseShared()方法
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
doReleaseShared方法主要的作用是唤醒他的后驱节点执行,而后驱节点醒过来
醒来后继续执行下一次循环去尝试获得锁