一、定义
一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire()
,然后再获取该许可。每个release()
添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore
只对可用许可的号码进行计数,并采取相应的行动。
Semaphore通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
二、使用场景代码示例
比方说我们有个资源访问连接池,每次只能同时允许2个线程访问资源,当某个线程或许到资格访问资源业务完成线程结束,它还要自动释放,让其它线程可以访问。
1 public class Test { 2 3 public static void main(String[] args) throws IOException { 4 ExecutorService executorService = Executors.newCachedThreadPool(); 5 // 配置同时只能有两个线程访问 6 Semaphore semaphore = new Semaphore(2); 7 // 开启10个线程 8 for (int i = 0; i < 10; i++) { 9 executorService.execute(new TaskRunn(semaphore)); 10 } 11 // 关闭线程池 12 executorService.shutdown(); 13 while (true) { 14 System.out.println(Thread.currentThread().getName()+"semaphore这个信号量中当前可用的许可数:"+semaphore.availablePermits()); 15 System.out.println(Thread.currentThread().getName()+"正在等待获取的线程的估计数目:"+semaphore.getQueueLength()); 16 // System.out.println(Thread.currentThread().getName()+"查询是否有线程正在等待获取:"+semaphore.hasQueuedThreads()); 17 if (semaphore.getQueueLength() == 0) { 18 break; 19 } 20 try { 21 Thread.sleep(1000); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } 26 } 27 } 28 29 class TaskRunn implements Runnable{ 30 31 private Semaphore semaphore; 32 public TaskRunn(Semaphore semaphore) { 33 this.semaphore = semaphore; 34 } 35 36 @Override 37 public void run() { 38 try { 39 System.out.println(Thread.currentThread().getName()+"begin..."); 40 semaphore.acquire();// 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断 41 Thread.sleep(5000);// 模拟业务耗时 42 semaphore.release();// 释放一个许可,将其返回给信号量 43 System.out.println(Thread.currentThread().getName()+"end..."); 44 } catch (InterruptedException e) { 45 e.printStackTrace(); 46 } 47 } 48 49 }
打印信息
mainsemaphore这个信号量中当前可用的许可数:2 main正在等待获取的线程的估计数目:0 pool-1-thread-1begin... pool-1-thread-2begin... pool-1-thread-3begin... pool-1-thread-4begin... pool-1-thread-5begin... mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:3 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:3 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:3 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:3 pool-1-thread-1end... pool-1-thread-2end... mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:1 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:1 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:1 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:1 mainsemaphore这个信号量中当前可用的许可数:0 main正在等待获取的线程的估计数目:1 pool-1-thread-3end... pool-1-thread-4end... mainsemaphore这个信号量中当前可用的许可数:1 main正在等待获取的线程的估计数目:0 mainsemaphore这个信号量中当前可用的许可数:1 main正在等待获取的线程的估计数目:0 mainsemaphore这个信号量中当前可用的许可数:1 main正在等待获取的线程的估计数目:0 mainsemaphore这个信号量中当前可用的许可数:1 main正在等待获取的线程的估计数目:0 mainsemaphore这个信号量中当前可用的许可数:1 main正在等待获取的线程的估计数目:0 pool-1-thread-5end... mainsemaphore这个信号量中当前可用的许可数:2 main正在等待获取的线程的估计数目:0