相关阅读
- JUC源码简析 AbstractQueuedSynchronizer
- JUC源码简析 Condition
- JUC源码简析 CountDownLatch
- JUC源码简析 CyclicBarrier
- JUC源码简析 ReentrantLock
简介
Semaphore
是一个线程同步的辅助类,内部维护了当前访问自身的线程个数,并提供同步机制;
使用Semaphore
可以控制同时访问资源的线程个数。
源码简析
内部类——Sync
简介
继承自AbstractQueuedSynchronizer
,重写了父类的tryReleaseShared
方法;提供了nonfairTryAcquireShared
、reducePermits
、drainPermits
方法;
tryReleaseShared
protected final boolean tryReleaseShared(int releases) {
// 死循环保证释放锁成功,存在多线程同时修改共享锁资源状态
for (;;) {
int current = getState();
int next = current + releases;
if (next < current)
// 资源计数发生反转,需要抛出错误
throw new Error("Maximum permit count exceeded");
// CAS尝试更新锁资源
// 更新失败,存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
if (compareAndSetState(current, next))
// true表示释放锁成功
return true;
}
}
nonfairTryAcquireShared
final int nonfairTryAcquireShared(int acquires) {
// 死循环保证尝试获取锁成功若存在共享锁资源的话,存在多线程同时修改共享锁资源状态
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
// 无共享锁资源可获取则直接退出,返回当前共享锁资源状态
// 否则CAS尝试更新锁资源
// 更新成功,则可以退出,返回当前共享锁资源状态
// 更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
return remaining;
}
}
reducePermits
final void reducePermits(int reductions) {
// 死循环保证执行成功,存在多线程同时修改共享锁资源状态
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current)
// 资源计数发生反转,需要抛出错误
throw new Error("Permit count underflow");
// CAS尝试更新锁资源
if (compareAndSetState(current, next))
// 更新成功,则可以退出
// 更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
return;
}
}
drainPermits
final int drainPermits() {
// 死循环保证执行成功,存在多线程同时修改共享锁资源状态
for (;;) {
int current = getState();
// 无共享锁资源可获取则直接退出,返回当前共享锁资源状态
// 否则CAS尝试更新锁资源
// 更新成功,则可以退出,返回当前共享锁资源状态
// 更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
内部类——NonfairSync
简介
继承内部类Sync
,实现非公平信号量相关操作;
需要实现的方法为:来自父类Sync
继承的AbstractQueuedSynchronizer
的抽象方法tryAcquireShared
;
tryAcquireShared
protected int tryAcquireShared(int acquires) {
// 直接调用父类Sync的nonfairTryAcquireShared方法实现
return nonfairTryAcquireShared(acquires);
}
本方式是以不公平竞争锁的方式实现的,不公平的体现为:新线程没有考虑当前是否已存在其它线程在等待获取锁,而是直接尝试获取锁;如果此时持有锁的线程恰好释放锁,那么新线程就可能获取锁成功,被释放锁线程唤醒的后继节点线程会因获取锁失败,再次设置头节点(头节点没有变化)的等待状态为SIGNAL
,然后挂起,等待新线程释放锁时唤醒自身;
内部类——FairSync
简介
继承内部类Sync
,实现公平信号量相关操作;
需要实现的方法为:来自父类Sync
继承的AbstractQueuedSynchronizer
的抽象方法tryAcquireShared
;
tryAcquireShared
protected int tryAcquireShared(int acquires) {
// 死循环保证执行成功,存在多线程同时修改共享锁资源状态
for (;;) {
if (hasQueuedPredecessors())
// 如果存在等待获取锁的线程,那么直接返回-1,表示获取锁失败
return -1;
int available = getState();
int remaining = available - acquires;
// 无共享锁资源可获取则直接退出,返回当前共享锁资源状态
// 否则CAS尝试更新锁资源
// 更新成功,则可以退出,返回当前共享锁资源状态
// 更新失败,因为存在其它线程同时尝试获取/释放锁,那么需要进行下一循环
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
// AbstractQueuedSynchronizer
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
// 头节点就是尾节点,则队列没有其它等待节点
// 队列存在节点,且
// 头节点的next不存在,即此时有新节点插入队列,刚更新尾节点,还未来得及更新旧尾节点的next,那么队列中存在其它等待节点(新节点)
// 或者存在但不是本线程,那么队列中有其它等待节点
// 否则,不存在其它等待节点,因为头节点的next就是本线程节点,这是等待队列中的节点线程尝试获取锁的情况
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
本方式是以公平竞争锁的方式实现的,公平的体现为:新线程在尝试获取锁之前,会先考虑当前是否已存在其它线程在等待获取锁,如果存在则直接放弃获取锁;如果不存在,才尝试获取锁;
Semaphore
构造函数
public Semaphore(int permits) {
// 默认是非公平信号量,使用场景更多
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
acquire
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void acquire(int permits) throws InterruptedException {
// 校验入参
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
acquireUninterruptibly
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
public void acquireUninterruptibly(int permits) {
// 校验入参
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);
}
tryAcquire
public boolean tryAcquire() {
// 返回值不小于0则表示成功获取到锁
return sync.nonfairTryAcquireShared(1) >= 0;
}
public boolean tryAcquire(int permits) {
// 校验入参
if (permits < 0) throw new IllegalArgumentException();
// 返回值不小于0则表示成功获取到锁
return sync.nonfairTryAcquireShared(permits) >= 0;
}
release
public void release() {
sync.releaseShared(1);
}
public void release(int permits) {
// 校验入参
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
其它方法
public int availablePermits() {
return sync.getPermits();
}
public int drainPermits() {
return sync.drainPermits();
}
protected void reducePermits(int reduction) {
// 校验入参
if (reduction < 0) throw new IllegalArgumentException();
sync.reducePermits(reduction);
}
测试
Demo
class Demo {
private int parties = 5;
private Semaphore semaphore = new Semaphore(2);
public static void main(String[] args) throws InterruptedException {
Demo demo = new Demo();
ExecutorService es = Executors.newFixedThreadPool(demo.parties);
for (int i=0; i<demo.parties; i++) {
es.execute(new SemaphoreTask(i, demo.semaphore));
}
es.shutdown();
}
private static class SemaphoreTask implements Runnable {
private Semaphore semaphore;
private int index;
SemaphoreTask(int index, Semaphore semaphore) {
this.semaphore = semaphore;
this.index = index;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("Thread:" + index + " waits to acquire semaphore");
semaphore.acquire();
System.out.println("Thread:" + index + " has acquired semaphore");
TimeUnit.SECONDS.sleep(2);
semaphore.release();
System.out.println("Thread:" + index + " has released semaphore");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试结果
Thread:0 waits to acquire semaphore
Thread:0 has acquired semaphore
Thread:2 waits to acquire semaphore
Thread:2 has acquired semaphore
Thread:1 waits to acquire semaphore
Thread:3 waits to acquire semaphore
Thread:4 waits to acquire semaphore
Thread:0 has released semaphore
Thread:1 has acquired semaphore
Thread:2 has released semaphore
Thread:3 has acquired semaphore
Thread:1 has released semaphore
Thread:4 has acquired semaphore
Thread:3 has released semaphore
Thread:4 has released semaphore