简单示例
public class SemaphoreTest {
public static void main(String[] args) {
//最多支持3个人同时蹲坑
Semaphore semaphore = new Semaphore(3);
//5个人来抢坑位
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "已经在蹲坑");
//模拟蹲坑时长
Thread.sleep((long) (Math.random() * 10 * 1000));
//离开坑位
System.out.println(Thread.currentThread().getName() + "即将离开坑位");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, i + "号").start();
}
}
}
输出如下:
0号已经在蹲坑
1号已经在蹲坑
2号已经在蹲坑
2号即将离开坑位
3号已经在蹲坑
0号即将离开坑位
4号已经在蹲坑
1号即将离开坑位
4号即将离开坑位
3号即将离开坑位
源码分析
构造方法
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
}
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
Sync(int permits) {
setState(permits);
}
}
acquire()
获取令牌,获取到线程可以继续执行,否则将会被阻塞
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
AbstractQueuedSynchronizer#acquireSharedInterruptibly
。
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
Semaphore.NonfairSync#tryAcquireShared
。
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
Semaphore.Sync#nonfairTryAcquireShared
,remaining =可用令牌数-需求数<0时,直接返回remaining 。否则利用CAS进行更新,同样返回remaining 。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
AbstractQueuedSynchronizer#doAcquireSharedInterruptibly
,阻塞当前线程
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;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
release()
public void release() {
sync.releaseShared(1);
}
AbstractQueuedSynchronizer#releaseShared
。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
Semaphore.Sync#tryReleaseShared
。将可用令牌数+1。更新成功后,返回ture。
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;
}
}
AbstractQueuedSynchronizer#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;
}
}
总结一下
- 初始化,设置state为固定值
- 获取令牌,state–。当state<0的时候,进行阻塞。
- 释放令牌,state++。对阻塞线程进行唤醒。