一、Semaphore简介
Semaphore(信号量)是一个线程同步工具,主要用于在一个时刻允许多个线程对共享资源进行并行操作的场景。通常情况下,使用Semaphore的过程实际上是多个线程获取访问共享资源许可证的过程,下面是Semaphore的内部处理逻辑。
▪ 如果此时Semaphore内部的计数器大于零,那么线程将可以获得小于该计数器数量的许可证,同时还会导致Semaphore内部的计数器减少所发放的许可证数量。
▪ 如果此时Semaphore内部的计数器等于0,也就是说没有可用的许可证,那么当前线程有可能会被阻塞(使用tryAcquire方法时不会阻塞)。
▪ 当线程不再使用许可证时,需要立即将其释放以供其他线程使用,所以建议将许可证的获取以及释放动作写在try..finally语句块中。
二、Semaphore的使用
2.1、主要方法
Semaphore semaphore=new Semaphore(10,true);//构造公平同步器,默认为非公平同步器。
semaphore.tryAcquire();//尝试获取一个许可证,不阻塞
semaphore.tryAcquire(5,TimeUnit.SECONDS);//5秒内,尝试获取许可证
semaphore.tryAcquire(3);//尝试获取3个许可证,不阻塞
semaphore.tryAcquire(3,5,TimeUnit.SECONDS);//5秒内尝试获取3个许可证
semaphore.acquire();//尝试获取许可证,此为阻塞方法
semaphore.acquire(5);//尝试获取5个许可证
int num = semaphore.availablePermits();//获取当前许可证数量
semaphore.release();//释放一个许可证
semaphore.release(5);//释放5个许可证
3.2、Semaphore使用
三、Semaphore方法详解
public class Semaphore implements java.io.Serializable {
//定义Semaphore指定许可证数量,并且指定非公平的同步器,因此new Semaphore(n)实际上是等价于newSemaphore(n,false)的。
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
//定义Semaphore指定许可证数量的同时给定非公平或是公平同步器。
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
//尝试获取Semaphore的许可证,该方法只会向Semaphore申请一个许可证,在Semaphore内部的可用许可证数量大于等于1的情况下,许可证将会获取成功,反之获取许可证则会失败,并且返回结果为false。
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
//该方法与tryAcquire无参方法类似,同样也是尝试获取一个许可证,但是增加了超时参数。如果在超时时间内还是没有可用的许可证,那么线程就会进入阻塞状态,直到到达超时时间或者在超时时间内有可用的证书(被其他线程释放的证书),或者阻塞中的线程被其他线程执行了中断。
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//在使用无参的tryAcquire时只会向Semaphore尝试获取一个许可证,但是该方法会向Semaphore尝试获取指定数目的许可证。
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));
}
//该方法会向Semaphore获取一个许可证,如果获取不到就会一直等待,直到Semaphore有可用的许可证为止,或者被其他线程中断。当然,如果有可用的许可证则会立即返回。
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//该方法会向Semaphore获取指定数量的许可证,如果获取不到就会一直等待,直到Semaphore有可用的相应数量的许可证为止,或者被其他线程中断。同样,如果有可用的permits个许可证则会立即返回。
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
//该方法会向Semaphore获取一个许可证,如果获取不到就会一直等待,与此同时对该线程的任何中断操作都会被无视,直到Semaphore有可用的许可证为止。当然,如果有可用的许可证则会立即返回。
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
//该方法会向Semaphore获取指定数量的许可证,如果获取不到就会一直等待,与此同时对该线程的任何中断操作都会被无视,直到Semaphore有可用的许可证为止,或者被其他线程中断。同样,如果有可用的permits个许可证则会立即返回。
public void acquireUninterruptibly(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);
}
//释放一个许可证,并且在Semaphore的内部,可用许可证的计数器会随之加一,表明当前有一个新的许可证可被使用。
public void release() {
sync.releaseShared(1);
}
//释放指定数量(permits)的许可证,并且在Semaphore内部,可用许可证的计数器会随之增加permits个,表明当前又有permits个许可证可被使用。
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
//当前的Semaphore还有多少个可用的许可证。
public int availablePermits() {
return sync.getPermits();
}
//排干Semaphore的所有许可证,以后的线程将无法获取到许可证,已经获取到许可证的线程将不受影响。
public int drainPermits() {
return sync.drainPermits();
}
}