Semaphore用于控制同一时刻允许获取锁的线程个数。通过构造器Semaphore(int permits)来初始化许可数,如:
Semaphore s = new Semaphore(3),通过构造器传入3,此时s最多允许3个线程同时获取锁,在没有线程释放锁的情况下,其它线程只能等待。值得一提的是,如果许可数初始化为0,s = new Semaphore(0),此时并不代表所有线程都无法获取锁,如果其中某一个线程抢先执行了s.release(3),那么其它线程也可获取到锁,release(3)代表往Semaphore释放了3个许可,此时是的许可总数变为3,因此s又可以允许同时3个线程获取到锁。
Semaphore获取锁的方式可分为两种模式:
1.公平模式
此模式下一旦有线程释放锁,那么在等待队列中的线程会优先获取到锁,新来的想获取锁的线程将排在等待队列中的线程的后面,严格遵循先进先出原则。
2.非公平模式
此模式下一旦有线程释放锁,那么新来的线程有可能比等待队列中的线程抢先一步获取到锁,通俗地讲,新来的线程和等待队列中的线程处于同等地位,谁快谁抢到锁,抢占式的不遵循先进先出原则,因此属于非公平模式。
构造器:
//默认创建基于非公平模式,并指定初始许可数
1. public Semaphore(int permits)
//可以同时指定模式和初始许可数
2. public Semaphore(int permits, boolean fair)
public方法:
//获取一个许可(锁),成功获取反回,获取失败则等待,直到有可用锁或当前线程被中断后返回
3. public void acquire() throws InterruptedException
///获取一个许可(锁),成功获取反回,获取失败则等待,直到有可用锁后返回,此方法不响应中断
4. public void acquireUninterruptibly()
//尝试获取一个许可,成功反回true,失败返回false,非阻塞方法
5. public boolean tryAcquire()
//尝试获取一个许可,在等待时间内成功反回true,失败返回false
6. public boolean tryAcquire(long timeout, TimeUnit unit)
//尝试获取指定数量的许可,如果剩余许可数大于等于permits则成功返回,否则等待,直到有可用许可数或当前线程被中断后返回
7. public void acquire(int permits) throws InterruptedException
//尝试获取指定数量的许可,如果剩余许可数大于等于permits则成功返回,否则等待,直到有可用许可数后返回,此方法不响应中断
8. public void acquireUninterruptibly(int permits)
//尝试获取指定数量的许可,如果剩余许可数大于等于permits则返回true,否则false
9. public boolean tryAcquire(int permits)
//尝试获取指定数量的许可,如果在等待时间内有剩余许可数大于等于permits则返回true,否则false
10. public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
//释放一个许可(总许可数加1)
11. public void release()
//释放指定数量的许可(总许可数加permits)
12. public void release(int permits)
//返回当前可用许可总数,对于s = new Semaphore(0);s.release(3)那么返回许可总数是3!
13. public int availablePermits()
//将许可总数设置为0
14. public int drainPermits()
//是否是公平模式
15. public boolean isFair()
//是否有线程在等待队列中等待锁释放
16. public final boolean hasQueuedThreads()
//等待队列中等待获取锁的线程的数量
17. public final int getQueueLength()
protected方法:
//从总许可数中减去指定许可数reduction
1. protected void reducePermits(int reduction)
//返回等待队列中等待获取锁的线程实例
2. protected Collection<Thread> getQueuedThreads()
package java.util.concurrent;
import java.util.Collection;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class Semaphore implements java.io.Serializable {
private static final long serialVersionUID = -3222578661600680210L;
/** All mechanics via AbstractQueuedSynchronizer subclass */
private final Sync sync;
//主要继承模板类实现相关try方法(tryAcquireShared、tryReleaseShared)
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
Sync(int permits) {
//通过AbstractQueuedSynchronizer内部提供的state整型属性保存许可数量
//子类FairSync与NonfairSync构造器都会调用
setState(permits);
}
//返回许可数
final int getPermits() {
return getState();
}
//非公平模式下尝试获取指定许可数
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
//比较再设置,防止其它线程已经修改了剩余许可数
compareAndSetState(available, remaining))
return remaining;
}
}
//释放指定数量的许可
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;
}
}
//减少许可总数
final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current) // underflow
throw new Error("Permit count underflow");
if (compareAndSetState(current, next))
return;
}
}
//将许可数设置为0
final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}
/**
* NonFair version
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
/**
* Fair version
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
for (;;) {
//公平模式和非公平模式的唯一区别就在于这一行代码判断
//如果发现AbstractQueuedSynchronizer的链中已经有等待的线程了,直接返回-1
//言下之意:只要还有线程在等待,我更要等待,因为我在它们后面。
//非公平模式不判断队列中是否有线程,直接查看许可数,有就尝试获取锁
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
}
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
//获取一个许可,调用AbstractQueuedSynchronizer.acquireSharedInterruptibly(1)
//acquireSharedInterruptibly(1)代表获取一个共享可中断的锁
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void release() {
sync.releaseShared(1);
}
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
public void acquireUninterruptibly(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);
}
public boolean tryAcquire(int permits) {
if (permits < 0) throw new IllegalArgumentException();
return sync.nonfairTryAcquireShared(permits) >= 0;
}
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}
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);
}
public boolean isFair() {
return sync instanceof FairSync;
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public final int getQueueLength() {
return sync.getQueueLength();
}
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
public String toString() {
return super.toString() + "[Permits = " + sync.getPermits() + "]";
}
}