并发库应用之七 & 信号灯Semaphore应用

  Semaphore可以维护当前访问自身的线程个数,并且提供了同步机制。

  Semaphore实现的功能类似于厕所里有5个坑,有10个人要上厕所,同时就只能有5个人占用,当5个人中 的任何一个让开后,其中在等待的另外5个人中又有一个可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项(常见于 限流 机制场景应用中):

  Semaphore(int permits)

  Semaphore(int permits, boolean fair)

  JDK包位置:java.util.concurrent.Semaphore

  一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。

  Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。例如,下面的类使用信号量控制对内容池的访问:

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3 import java.util.concurrent.Semaphore;
 4 
 5 public class SemaphoreTest {
 6     public static void main(String[] args) {
 7         //线程数动态变化,来一个就产生一个线程
 8         ExecutorService service = Executors.newCachedThreadPool();
 9         //可容纳的线程并发数
10         final Semaphore sp = new Semaphore(3);
11         for (int i = 0; i < 10; i++) {
12             Runnable runnable = new Runnable() {
13                 public void run() {
14                     try {
15                         //从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断
16                         sp.acquire();
17                     } catch (InterruptedException e1) {
18                         e1.printStackTrace();
19                     }
20                     System.out.println(String.format("线程%s进入,当前已有%d个并发", Thread.currentThread().getName(), (3 - sp.availablePermits())));
21                     try {
22                         Thread.sleep((long) (Math.random() * 10000));
23                     } catch (InterruptedException e) {
24                         e.printStackTrace();
25                     }
26                     System.out.println(String.format("线程【%s】已经离开-------BYE BYE", Thread.currentThread().getName()));
27                     sp.release();//释放一个许可,将其返回给信号量
28                 }
29             };
30             service.execute(runnable);//提交了10个任务放入到线程队列
31         }
32         try {
33             while (true) {
34                 if (sp.availablePermits() == 3) {
35                     System.out.println("****************所有线程执行完毕****************");
36                     break;
37                 }
38             }
39         } finally {
40             service.shutdown();
41         }
42     }
43 }

上述代码运行结果如下所示:

  

  总结:传统互斥只能内部释放锁this.unlock(),进去this.lock()晕倒了别人就没法进去了;单个信号量的Semaphore对象也可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,sp.release()  sp.acquire()。这可应用于死锁恢复的一些场合

提示:欢迎继续参看我相关的下一篇博客:并发库应用之八 & 循环路障CyclicBarrier应用

 

posted @ 2017-03-09 15:46  星火燎原智勇  阅读(362)  评论(0编辑  收藏