一、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();}}
