线程:Semaphore实现信号灯
Semaphore是一个计数的信号量,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如实现一个文件允许的线程访问数。打个通俗的比喻,Semaphore实现的功能类似厕所有4个坑,假如有10个人上厕所,那么同时有多少个人去上厕所呢?同时只能有4个人能够占用,当4个人中的任何一个人让开后,其中在等待的另外6个人又有一个可以占用了。
1 package ch03; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 import java.util.concurrent.Semaphore; 6 7 public class SemaphoreTest { 8 9 public static void main(String[] args) { 10 ExecutorService threadPool = Executors.newCachedThreadPool(); 11 //获取三个许可的信号灯 12 final Semaphore sp = new Semaphore(5); 13 for(int i=1; i<=10; i++){ 14 final int index = i; 15 Runnable runable = new Runnable() { 16 17 @Override 18 public void run() { 19 try { 20 //获取一个信号灯 21 sp.acquire(); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 System.out.println("有一个"+Thread.currentThread().getName()+ 26 "线程进来了,当前有"+(5-sp.availablePermits())+"线程正在并发..."); 27 28 try { 29 Thread.sleep(index * 1000); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 //释放信号灯 34 sp.release(); 35 System.out.println("线程"+Thread.currentThread().getName()+"离开了,现在还有"+(5-sp.availablePermits())+"个线程!"); 36 } 37 }; 38 threadPool.execute(runable); 39 } 40 threadPool.shutdown(); 41 } 42 43 }
至于,在等待的6个人中谁先进去,有两种方式:一种是看谁快,第二种是按排序,先来的先进去。可以通过Semaphore的构造函数指定:
如果使用排序的方式,可以将fair设为true.
除此之外,单个信号量的Semaphore对象还可以实现互斥锁的功能,只有一个灯,A线程获得,B线程就等着。传统的互斥锁,同一个线程的锁只能由自己释放,但Semaphore对象的互斥锁可以是由一个线程获得锁,再由另外一个线程释放锁,可以应用于死锁恢复的场合。比如一个人进厕所后,晕在里面了,这样的话可以去找管理员拿备用钥匙,打开门将人挪出来,这样就避免后面的人一直堵在这里。