关于java:java并发编程基于信号量semaphore实现限流器

10次阅读

共计 2376 个字符,预计需要花费 6 分钟才能阅读完成。

[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 把锅               => 备注:被还回能力被再次占用,不超过 3
Thread- 0 还回一把锅,还剩 1 把锅
Thread- 4 拿走了一把锅,还剩 0 把锅               => 备注:被还回能力被再次占用,不超过 3
Thread- 2 还回一把锅,还剩 1 把锅        
Thread- 3 还回一把锅,还剩 2 把锅
Thread- 4 还回一把锅,还剩 3 把锅                  => 备注:用完顺次开释

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

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

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

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