Java并发中,如何用信号量Semaphore构建高效限流器?

2026-05-25 12:061阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1550个文字,预计阅读时间需要7分钟。

Java并发中,如何用信号量Semaphore构建高效限流器?

目录

一、什么是信号量

二、信号量(Semaphore)的使用

三、信号量在编程技术中的应用

一、什么是信号量

信号量是一种用于多线程编程中的同步机制,用于控制对共享资源的访问,确保同一时间只有一个线程可以访问该资源。

二、信号量(Semaphore)的使用在编程中,信号量通常使用单词semaphore来表示。它是一种特殊的变量,用于同步线程的执行。

三、信号量在编程技术中的应用信号量在编程技术中广泛应用于多线程编程和并发控制。通过使用信号量,可以避免多个线程同时访问共享资源,从而防止数据竞争和死锁等问题。

目录
  • 一、什么是信号量
  • 二、信号量类Semaphore
  • 三、实现限流器
  • 欢迎关注我的博客,更多精品知识合集

Java并发中,如何用信号量Semaphore构建高效限流器?

一、什么是信号量

“信号量”在编程术语中使用单词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微服务从青铜到王者》

本文共计1550个文字,预计阅读时间需要7分钟。

Java并发中,如何用信号量Semaphore构建高效限流器?

目录

一、什么是信号量

二、信号量(Semaphore)的使用

三、信号量在编程技术中的应用

一、什么是信号量

信号量是一种用于多线程编程中的同步机制,用于控制对共享资源的访问,确保同一时间只有一个线程可以访问该资源。

二、信号量(Semaphore)的使用在编程中,信号量通常使用单词semaphore来表示。它是一种特殊的变量,用于同步线程的执行。

三、信号量在编程技术中的应用信号量在编程技术中广泛应用于多线程编程和并发控制。通过使用信号量,可以避免多个线程同时访问共享资源,从而防止数据竞争和死锁等问题。

目录
  • 一、什么是信号量
  • 二、信号量类Semaphore
  • 三、实现限流器
  • 欢迎关注我的博客,更多精品知识合集

Java并发中,如何用信号量Semaphore构建高效限流器?

一、什么是信号量

“信号量”在编程术语中使用单词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微服务从青铜到王者》