一、Semaphore简介

Semaphore(信号量)是一个线程同步工具,主要用于在一个时刻允许多个线程对共享资源进行并行操作的场景。通常情况下,使用Semaphore的过程实际上是多个线程获取访问共享资源许可证的过程,下面是Semaphore的内部处理逻辑。

▪ 如果此时Semaphore内部的计数器大于零,那么线程将可以获得小于该计数器数量的许可证,同时还会导致Semaphore内部的计数器减少所发放的许可证数量。
▪ 如果此时Semaphore内部的计数器等于0,也就是说没有可用的许可证,那么当前线程有可能会被阻塞(使用tryAcquire方法时不会阻塞)。
▪ 当线程不再使用许可证时,需要立即将其释放以供其他线程使用,所以建议将许可证的获取以及释放动作写在try..finally语句块中。

二、Semaphore的使用

2.1、主要方法

  1. Semaphore semaphore=new Semaphore(10,true);//构造公平同步器,默认为非公平同步器。
  2. semaphore.tryAcquire();//尝试获取一个许可证,不阻塞
  3. semaphore.tryAcquire(5,TimeUnit.SECONDS);//5秒内,尝试获取许可证
  4. semaphore.tryAcquire(3);//尝试获取3个许可证,不阻塞
  5. semaphore.tryAcquire(3,5,TimeUnit.SECONDS);//5秒内尝试获取3个许可证
  6. semaphore.acquire();//尝试获取许可证,此为阻塞方法
  7. semaphore.acquire(5);//尝试获取5个许可证
  8. int num = semaphore.availablePermits();//获取当前许可证数量
  9. semaphore.release();//释放一个许可证
  10. semaphore.release(5);//释放5个许可证

3.2、Semaphore使用

三、Semaphore方法详解

  1. public class Semaphore implements java.io.Serializable {
  2. //定义Semaphore指定许可证数量,并且指定非公平的同步器,因此new Semaphore(n)实际上是等价于newSemaphore(n,false)的。
  3. public Semaphore(int permits) {
  4. sync = new NonfairSync(permits);
  5. }
  6. //定义Semaphore指定许可证数量的同时给定非公平或是公平同步器。
  7. public Semaphore(int permits, boolean fair) {
  8. sync = fair ? new FairSync(permits) : new NonfairSync(permits);
  9. }
  10. //尝试获取Semaphore的许可证,该方法只会向Semaphore申请一个许可证,在Semaphore内部的可用许可证数量大于等于1的情况下,许可证将会获取成功,反之获取许可证则会失败,并且返回结果为false。
  11. public boolean tryAcquire() {
  12. return sync.nonfairTryAcquireShared(1) >= 0;
  13. }
  14. //该方法与tryAcquire无参方法类似,同样也是尝试获取一个许可证,但是增加了超时参数。如果在超时时间内还是没有可用的许可证,那么线程就会进入阻塞状态,直到到达超时时间或者在超时时间内有可用的证书(被其他线程释放的证书),或者阻塞中的线程被其他线程执行了中断。
  15. public boolean tryAcquire(long timeout, TimeUnit unit)
  16. throws InterruptedException {
  17. return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
  18. }
  19. //在使用无参的tryAcquire时只会向Semaphore尝试获取一个许可证,但是该方法会向Semaphore尝试获取指定数目的许可证。
  20. public boolean tryAcquire(int permits) {
  21. if (permits < 0) throw new IllegalArgumentException();
  22. return sync.nonfairTryAcquireShared(permits) >= 0;
  23. }
  24. //在一定时间尝试获取一定数量的许可证
  25. public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
  26. throws InterruptedException {
  27. if (permits < 0) throw new IllegalArgumentException();
  28. return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
  29. }
  30. //该方法会向Semaphore获取一个许可证,如果获取不到就会一直等待,直到Semaphore有可用的许可证为止,或者被其他线程中断。当然,如果有可用的许可证则会立即返回。
  31. public void acquire() throws InterruptedException {
  32. sync.acquireSharedInterruptibly(1);
  33. }
  34. //该方法会向Semaphore获取指定数量的许可证,如果获取不到就会一直等待,直到Semaphore有可用的相应数量的许可证为止,或者被其他线程中断。同样,如果有可用的permits个许可证则会立即返回。
  35. public void acquire(int permits) throws InterruptedException {
  36. if (permits < 0) throw new IllegalArgumentException();
  37. sync.acquireSharedInterruptibly(permits);
  38. }
  39. //该方法会向Semaphore获取一个许可证,如果获取不到就会一直等待,与此同时对该线程的任何中断操作都会被无视,直到Semaphore有可用的许可证为止。当然,如果有可用的许可证则会立即返回。
  40. public void acquireUninterruptibly() {
  41. sync.acquireShared(1);
  42. }
  43. //该方法会向Semaphore获取指定数量的许可证,如果获取不到就会一直等待,与此同时对该线程的任何中断操作都会被无视,直到Semaphore有可用的许可证为止,或者被其他线程中断。同样,如果有可用的permits个许可证则会立即返回。
  44. public void acquireUninterruptibly(int permits) {
  45. if (permits < 0) throw new IllegalArgumentException();
  46. sync.acquireShared(permits);
  47. }
  48. //释放一个许可证,并且在Semaphore的内部,可用许可证的计数器会随之加一,表明当前有一个新的许可证可被使用。
  49. public void release() {
  50. sync.releaseShared(1);
  51. }
  52. //释放指定数量(permits)的许可证,并且在Semaphore内部,可用许可证的计数器会随之增加permits个,表明当前又有permits个许可证可被使用。
  53. public void release(int permits) {
  54. if (permits < 0) throw new IllegalArgumentException();
  55. sync.releaseShared(permits);
  56. }
  57. //当前的Semaphore还有多少个可用的许可证。
  58. public int availablePermits() {
  59. return sync.getPermits();
  60. }
  61. //排干Semaphore的所有许可证,以后的线程将无法获取到许可证,已经获取到许可证的线程将不受影响。
  62. public int drainPermits() {
  63. return sync.drainPermits();
  64. }
  65. }

四、扩展Semaphore增强release