Semaphore简介
public class SemaphoreDemo {
public static void main(String[] args) {
//第二个参数可以配置是否是公平信号量
final Semaphore semaphore = new Semaphore(3, true);
new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
Thread.sleep(200);
System.out.println(Thread.currentThread().getId() + "已运行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire(3);
Thread.sleep(200);
System.out.println(Thread.currentThread().getId() + "已运行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(3);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire(2);
Thread.sleep(200);
System.out.println(Thread.currentThread().getId() + "已运行");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(2);
}
}
}).start();
}
}
-
Semaphore:信号量,继承AQS使用其共享模式,初始化其state值,表示资源值
-
acquire(n):将state值减n,成功即获取资源
-
release(n):将state值加n,成功即释放资源
以公平信号量为例解析acquire()流程
-
公平信号量和非公平信号量不同:非公平信号量会直接尝试获取资源,而公平信号量会查看阻塞队列是否有线程等待
-
公平信号量和非公平信号量相同:release()相同
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//AQS中的acquireSharedInterruptibly()
public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//Semaphore重写了此方法,以公平信号量为例,下面具体会写
if (tryAcquireShared(arg) < 0)
//将线程加入阻塞队列等待,具体见AQS源码阅读(三)
doAcquireSharedInterruptibly(arg);
}
//返回的remaining小于0:获取资源失败
protected int tryAcquireShared(int acquires) {
for (;;) {
//阻塞队列内是否有线程等待:具体见AQS源码阅读(一)
if (hasQueuedPredecessors())
return -1;
//情况一:阻塞队列内没有线程等待
//情况一:当前结点是阻塞队列的后继结点
//AQS中的state值
int available = getState();
//remaining:信号量剩余值
int remaining = available - acquires;
//remaining < 0:信号量资源值不足,获取失败
//compareAndSetState():CAS操作设置state值
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
解析release()流程
public void release() {
sync.releaseShared(1);
}
//AQS的releaseShared()
public final boolean releaseShared(int arg) {
//Semaphore重写了此方法,下面具体会写
if (tryReleaseShared(arg)) {
//唤醒阻塞队列中的线程,具体见AQS源码阅读(三)
doReleaseShared();
return true;
}
return false;
}
//自旋释放资源
protected final boolean tryReleaseShared(int releases) {
for (;;) {
////AQS中的state值
int current = getState();
//释放资源之后的state值
int next = current + releases;
//溢出
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
//CAS设置state值
if (compareAndSetState(current, next))
return true;
}
}