深入理解Semaphore(信号量)
Semaphore借助AQS
- Sync 继承 AbstractQueuedSynchronizer(AQS同步器)
- NonfairSync Sync的非公平实现
- FairSync Sync的公平实现
为什么没有实现Lock接口?
- 因为,lock和unlock没有参数,无法达到此效果
套路(同ReentrantLock)
- AQS操作,是集成AQS类作为静态内部类
- Sync默认是非公平的实现
- NonfairSync 非公平同步器
- FairSync 公平同步器
Semaphore的特性
- Semaphore是一个共享同步队列
- Semaphore主要是控住同一时间运行的线程数
- state标识当前运行的线程数
- 是可以响应中断的
源码分析
构造
Semaphore构造
//默认识非公平同步队列
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
Semaphore.Sync构造
//permits表示,限制限号量,此时state==permits
Sync(int permits) {
setState(permits);
}
aquire()方法
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
//调用AQS的acquireSharedInterruptibly
sync.acquireSharedInterruptibly(permits);
}
//AQS
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 这里调用Semaphore的tryAcquireShared方法,如果<0,标识不能获取该资源锁,就会入队
if (tryAcquireShared(arg) < 0)
//可以被中断的入队操作
doAcquireSharedInterruptibly(arg);
}
//非公平的tryAcquireShared方法调用父类的nonfairTryAcquireShared方法
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
//这里remaining标识剩余的信号量
//remaining小于0会直接返回,在AQS只有>0的返回值才能获取资源锁
if (remaining < 0 ||
//CAS操作,对state进行赋值,成功设置state,此时信号量>0,即可获取资源锁
compareAndSetState(available, remaining))
return remaining;
}
}
//公平同步器的tryAcquireShared方法
protected int tryAcquireShared(int acquires) {
for (;;) {
//这里判断是否存在前继节点,存在就不可获取资源锁,能获取资源锁的之能事head节点
if (hasQueuedPredecessors())
return -1;
//同上操作
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
release()方法
//获取的时候,传入的信号值必须和释放的信号值相匹配
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
public final boolean releaseShared(int arg) {
//首先调用tryReleaseShared,该操作是一个资源操作,只可能返回true
if (tryReleaseShared(arg)) {
//进行释放,其实就是讲该节点从同步队列中移除,更新新的head指向的node引用
doReleaseShared();
return true;
}
return false;
}
//Syn统一实现了该方法,释放可以公用的
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");
//CAS操作,更新state的值
if (compareAndSetState(current, next))
return true;
}
}
Demo
总会是maxCount个线程一起执行,这里信号量规定了5个,而每次线程需要信号为1,那么就表示,该信号量支持5
个线程同时执行任务。也支持每个线程需要的信号不同,资源一定的情况下,每个线程消耗不一样,维持系统稳定。
/**
* describe:
* E-mail:yzzstyle@163.com date:2018/12/17
*
* @Since 0.0.1
*/
public class SemaphoreTest {
//信号量的permits
private final int maxCount;
private final Semaphore semaphore;
public SemaphoreTest(int maxCount) {
this.maxCount = maxCount;
//默认是nofair
this.semaphore = new Semaphore(maxCount);
}
public void add() {
try {
//获取到信号量
semaphore.acquire();
//操作
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}
class A extends Thread {
SemaphoreTest semaphoreTest;
public A(SemaphoreTest semaphoreTest) {
this.semaphoreTest = semaphoreTest;
}
@Override
public void run() {
semaphoreTest.add();
System.out.println("add:");
}
}
class Test {
public static void main(String[] args) {
SemaphoreTest semaphoreTest = new SemaphoreTest(5);
for (int i = 0; i < 10; i++) {
A a = new A(semaphoreTest);
a.start();
}
}
}