[TOC]

一、什么是信号量

“信号量”在编程术语中应用单词semaphore,那什么是“信号量”?信号量就好比你家厨房入口架子上摆了三把锅。

  • 如果你的孩子热奶拿走一把,你的老婆热汤拿走一把,你的妈妈做菜拿走一把,你想煮面条就没有锅了。当你看到这种状况,你就不会进入厨房了,你处于期待状态。也就说厨房依照“锅的数量”作为信号量,只能包容三个人(线程)。
  • 当你的老婆热完汤之后,把锅从新放回架子上,你就能够去取得一个锅,你就能够进入厨房了。

二、信号量类Semaphore

通过上文的介绍,咱们能够总结出信号量的重要组成部分

  • 计数器:计算信号量的应用状况,锅(信号)被应用一次减1,锅(信号)被还回一次加1
  • 期待队列:当工作数量大于信号量数量下限的时候,工作进入期待队列

信号量在JDK中是由 java.util.concurrent.Semaphore 实现的,Semaphore提供了两个构造函数。permits参数代表信号量的数量(锅的数量),fair代表信号量的获取是否遵循偏心准则。所谓的偏心准则就是:先启动的线程先调用semaphore.acquire();办法,就先失去一个信号“锅”(permit),遵循先来后到的准则。

public Semaphore(int permits)public Semaphore(int permits, boolean fair)

罕用办法列表

办法名作用
acquire()获取一个permit,在获取到permit之前,线程处于阻塞状态
tryAcquire()尝试获取一个permit,获取胜利返回true,否则返回false,不阻塞线程
tryAcquire(long timeout, TimeUnit unit)和tryAcquire()大部分实现一样,区别是提供超时设置,在超时工夫范畴内屡次尝试,不阻塞线程。
availablePermits()获取目前残余的信号permit的数量
release()开释一个permit,并唤醒一个期待信号permit的线程
hasQueuedThreads()返回值boolean类型,判断期待队列中是否存在期待线程
getQueueLength()获取期待队列中期待线程的数量

三、实现限流器

通过下面的介绍,我置信大家必定能够想到Semaphore的利用场景。比方:

  • 医院门诊排号器,三个在岗医生就是3个信号permit,当超出信号量数量的时候,想就诊就只能期待
  • 停车场停车性能,n个车位就是n个信号permit,当超出信号量数量的时候,想停车也只能期待

利用场景还有很多很多,大家本人去发会创造力吧。其实无论多少种利用场景说白了:Semaphore实现的就是一个限流器。咱们还是以咱们家的厨房kitchen外面的三把锅wok为例,实现基于信号量的限流。

public class TestKitchenSemaphore {  //信号量-3把锅  private  static Semaphore threeWoks = new Semaphore(3);  public static void main(String[] args) throws InterruptedException {    //模仿5集体抢占3把锅的场景    for(int i=0;i < 5;i++){      Thread.sleep(1000); //模仿进入厨房的先后顺序,存在工夫距离            new Thread(() -> {        try {          threeWoks.acquire();  //获取一个permit,信号量计数器减1          System.out.println(Thread.currentThread().getName()                  + "拿走了一把锅,还剩" + threeWoks.availablePermits() + "把锅");          Thread.sleep(new Random().nextInt(5000)); //模仿应用锅的时长          threeWoks.release();//开释permit,信号量计数器加1          System.out.println(Thread.currentThread().getName()                  + "还回一把锅,还剩" + threeWoks.availablePermits() + "把锅");        } catch (InterruptedException e) {          e.printStackTrace();        }      }).start();    }  }}

上文代码的输入如下,咱们能够看到每acquire一次信号量减1,每release一次信号量加1。信号量的下限是3,上限是0。当达到下限的时候,只有等先占据锅permit的线程开释,其余线程能力获取到锅permit。

Thread-0拿走了一把锅,还剩2把锅 Thread-1拿走了一把锅,还剩1把锅Thread-2拿走了一把锅,还剩0把锅               => 备注:5个线程只能获取3个锅(下限)Thread-1还回一把锅,还剩1把锅Thread-3拿走了一把锅,还剩0把锅               => 备注:被还回能力被再次占用,不超过3Thread-0还回一把锅,还剩1把锅Thread-4拿走了一把锅,还剩0把锅               => 备注:被还回能力被再次占用,不超过3Thread-2还回一把锅,还剩1把锅        Thread-3还回一把锅,还剩2把锅Thread-4还回一把锅,还剩3把锅                  => 备注:用完顺次开释

欢送关注我的博客,更多精品常识合集

本文转载注明出处(必须带连贯,不能只转文字):字母哥博客 - zimug.com

感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源!。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。

  • 《kafka修炼之道》
  • 《手摸手教你学Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2一本通》
  • 《实战前后端拆散RBAC权限管理系统》
  • 《实战SpringCloud微服务从青铜到王者》