前言
Semaphore对于线程来说相当于售票员,线程想继续执行,就需要向Semaphore买票,买到票则向下执行,没有买到则排队等待,其中对于每个线程来说有的线程需要买n多张票才能执行,Semaphore的用法类似与这个说法
方法说明
state的值对应state数量的许可证
public Semaphore(int permits)
创建state等于permits的非公平Semaphore
public Semaphore(int permits, boolean fair)
创建可选的公平/非公平的state等于permits的Semaphore
public void acquire() throws InterruptedException
申请一个许可证,申请不到则阻塞,可以被中断
public void acquireUninterruptibly()
申请一个许可证,申请不到则阻塞,不可以被中断
public boolean tryAcquire()
尝试申请一个许可证,申请不到返回false,申请的返回true
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException
尝试在一段时间内申请一个许可证,申请不到返回false,申请的返回true
public void release()
归还一个许可证
------------ 与上面方法类似,只不过上面是1个1个的,这里是大于0的整数 ------------
|public void acquire(int permits) throws InterruptedException |
|public void acquireUninterruptibly(int permits) |
|public boolean tryAcquire(int permits) |
|public boolean tryAcquire(int permits, long timeout, TimeUnit unit) |
| throws InterruptedException |
|public void release(int permits) |
------------------------------------------------------------------------------
public int availablePermits()
获取state的值
public int drainPermits()
设置state的值为0
public boolean isFair()
获取当前Semaphore是否公平
public final boolean hasQueuedThreads()
获取是否有线程等待在当前Semaphore上(不准改数量可变的,只具有参考价值)
public final int getQueueLength()
获取等待在Semaphore上线程的数量(不准改数量可变的,只具有参考价值)
源码分析
Semaphore也是基于AQS的共享模式,即Semaphore内部有一个继承AbstractQueuedSynchronizer的类Sync,并重写tryReleaseShared和tryAcquireShared方法。
与CountDownLatch不同的是:
tryAcquireShared:修改成功state的值,则返回1,否则返回-1,对AQS来说tryAcquireShared方法是用来判断线程是否可以出队列和入队列的判断方法,即正数表示当前线程不要排队
tryReleaseShared方法: 一般的实现方式是修改state的值,并返回修改成功与否的状态。返回的状态主要是用来判断当前锁是否可用,可用则唤醒CLH队列中的节点线程
我们知道AbstractQueuedSynchronizer对于Semaphore的实现就是state用来记录许可证的数目,而双向等待队列用来记录排队的线程
公平/非公平就是:每当一个线程需要获取许可证的时候,公平的执行方式,应该首先判断队列中是否有线程在等待,队列有则将当前线程入队等待
公平
protected int tryAcquireShared(int acquires) {
for (;;) {
/**
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
return
是否有节点的检查
h != t &&
节点线程的检查
((s = h.next) == null || s.thread != Thread.currentThread());
}
*/
if (
判断:队列中是否有等待线程
hasQueuedPredecessors()
)
return -1;
下面就是些CAS的赋值操作
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
非公平(与上述实现类似只是没有了等待节点的检查 hasQueuedPredecessors方法 )
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
acquire方法与CountDownLatch的await方法类似,只是它们二者tryAcquireShared上不同,
CountDownLatch的不修改state的值
Semaphore是有可能修改state的值
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
Semaphore的复用性
该方法直接增加state的值,即总是state开始时等于1,你也可以归还许可证,使其值等于2(or其他)
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;
}
}
总结:Semaphore的用法和原理很简单,只要知道Semaphore相当于一个检票员,每个线程只有向其出示需要的门票才能继续执行而不是等待,同时Semaphore也是可以自己生产票,只要调用release方法传入的参数n是正数就能新生n张门票