Semaphore 是什么

Semaphore 通常我们叫它信号量, 可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。

可以把它简单的理解成我们停车场入口立着的那个显示屏,每有一辆车进入停车场显示屏就会显示剩余车位减1,每有一辆车从停车场出去,显示屏上显示的剩余车辆就会加1,当显示屏上的剩余车位为0时,停车场入口的栏杆就不会再打开,车辆就无法进入停车场了,直到有一辆车从停车场出去为止。

使用场景

通常用于那些资源有明确访问数量限制的场景,常用于限流 。

比如:数据库连接池,同时进行连接的线程有数量限制,连接不能超过一定的数量,当连接达到了限制数量后,后面的线程只能排队等前面的线程释放了数据库连接才能获得数据库连接。

比如:停车场场景,车位数量有限,同时只能容纳多少台车,车位满了之后只有等里面的车离开停车场外面的车才可以进入。

在比如,接口限流 ,应用限流 ,商品限流…

Semaphore常用方法说明

acquire()
获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。tryAcquire(long timeout, TimeUnit unit)
尝试在指定时间内获得令牌,返回获取令牌成功或失败,不阻塞线程。
​
release()
释放一个令牌,唤醒一个获取令牌不成功的阻塞线程。
​
hasQueuedThreads()
等待队列里是否还存在等待线程。
​
getQueueLength()
获取等待队列里阻塞的线程数。
​
drainPermits()
清空令牌把可用令牌数置为0,返回清空令牌的数量。
​
availablePermits()
返回可用的令牌数量。// .....其他的自己看源码

用semaphore 实现停车场提示牌功能

每个停车场入口都有一个提示牌,上面显示着停车场的剩余车位还有多少,当剩余车位为0时,不允许车辆进入停车场,直到停车场里面有车离开停车场,这时提示牌上会显示新的剩余车位数。

业务场景 :

1、停车场容纳总停车量10。

2、当一辆车进入停车场后,显示牌的剩余车位数响应的减1.

3、每有一辆车驶出停车场后,显示牌的剩余车位数响应的加1。

4、停车场剩余车位不足时,车辆只能在外面等待。

public class TestCar {​//停车场同时容纳的车辆10private  static  Semaphore semaphore=new Semaphore(10);
​public static void main(String[] args) {​//模拟100辆车进入停车场for(int i=0;i<100;i++){​Thread thread=new Thread(new Runnable() {public void run() {try {System.out.println("===="+Thread.currentThread().getName()+"来到停车场");if(semaphore.availablePermits()==0){System.out.println("车位不足,请耐心等待");}semaphore.acquire();//获取令牌尝试进入停车场System.out.println(Thread.currentThread().getName()+"成功进入停车场");Thread.sleep(new Random().nextInt(10000));//模拟车辆在停车场停留的时间System.out.println(Thread.currentThread().getName()+"驶出停车场");semaphore.release();//释放令牌,腾出停车场车位} catch (InterruptedException e) {e.printStackTrace();}}},i+"号车");
​thread.start();
​}
​}
}

用semaphore 实现接口限流

package com.limiting.semaphore;import java.lang.annotation.*;@Documented@Target({ElementType.METHOD})//作用:方法
@Retention(RetentionPolicy.RUNTIME)
public @interface SemaphoreDoc {String key(); //建议设置不然可能发生,不同方法重复限流现象int limit() default 3;int blockingTime() default 3;}
package com.limiting.semaphore;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;@Component
@Aspect
public class SemaphoreAop {//这里需要注意了,这个是将自己自定义注解作为切点的根据,路径一定要写正确了@Pointcut(value = "@annotation(com.limiting.semaphore.SemaphoreDoc)")public void semaphoreDoc() {}//限流池private static  Map<String, Semaphore> map=new ConcurrentHashMap<>();@Around("semaphoreDoc()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {Object res = null;MethodSignature signature = (MethodSignature)joinPoint.getSignature();SemaphoreDoc annotation  = signature.getMethod().getAnnotation(SemaphoreDoc.class);int blockingTime = annotation.blockingTime();int limit = annotation.limit();String key = annotation.key();StringBuilder name = new StringBuilder(key+signature.getMethod().getName());//方法名for (String parameterName : signature.getParameterNames()) {name.append(parameterName);}Semaphore semaphore = map.get(name.toString());if (semaphore == null) {Semaphore semaphore1 = new Semaphore(limit);map.put(name.toString(),semaphore1);semaphore=semaphore1;}try {//获取令牌boolean b = semaphore.tryAcquire(blockingTime, TimeUnit.SECONDS);if (b) {//如果拿到令牌了那么执行方法try {res = joinPoint.proceed();} catch (Throwable e) {e.printStackTrace();}} else {//在一定时间内拿不到令牌那么就访问失败throw  new Exception("访问超时,目前请求人数过多请稍后在试");}} finally {//释放令牌,腾出位置semaphore.release();}return  res;}}

用semaphore 实现防止商品超卖

package com.limiting.semaphore;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;/*** 秒杀防止商品超卖现象*/
public class SemaphoreCommodity {//商品池private   Map<String, Semaphore> map=new ConcurrentHashMap<>();//初始化商品池public SemaphoreCommodity() {//手机10部map.put("phone",new Semaphore(10));//电脑4台map.put("computer",new Semaphore(4));}/**** @param name 商品名称* @return 购买是否成功*/public boolean getbuy(String name) throws Exception {Semaphore semaphore = map.get(name);while (true) {int availablePermit = semaphore.availablePermits();if (availablePermit==0) {//商品售空return  false;}boolean b = semaphore.tryAcquire(1, TimeUnit.SECONDS);if (b) {System.out.println("抢到商品了");///处理逻辑return  true;}}}public static void main(String[] args) throws Exception {SemaphoreCommodity semaphoreCommodity=new SemaphoreCommodity();for (int i = 0; i < 10; i++) {new Thread(()->{try {System.out.println(semaphoreCommodity.getbuy("computer"));} catch (Exception e) {e.printStackTrace();}}).start();}}}

点赞 -收藏-关注-便于以后复习和收到最新内容 有其他问题在评论区讨论-或者私信我-收到会在第一时间回复 如有侵权,请私信联系我 感谢,配合,希望我的努力对你有帮助^_^

Java多线程-Semaphore(限流)相关推荐

  1. java各层级限流对比,面试官说:来谈谈限流-从概念到实现,一问你就懵逼了?...

    后端服务的接口都是有访问上限的,如果外部qps或并发量超过了访问上限会导致应用瘫痪.所以一般都会对接口调用加上限流保护,防止超出预期的请求导致系统故障. 从限流类型来说一般来说分为两种:并发数限流和q ...

  2. java每秒限流_java限流工具类

    代码 import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.ConcurrentHashM ...

  3. java队列实现限流,java中应对高并发的两种策略

    目的:提高可用性 通过ExecutorService实现队列泄洪 //含有20个线程的线程池 private ExecutorService executorService = Executors.n ...

  4. java服务端限流框架,美团大众点评服务框架Pigeon

    服务框架Pigeon架构 ? Pigeon提供jar包接入 ,线上运行在tomcat里 ? Monitor-CAT ,负责调用链路分析.异常监控告警等 ? 配置中心-Lion ,负责一些开关配置读取 ...

  5. Java实现漏斗限流算法

    前言 最近在学习老钱的<Redis深度历险:核心原理与应用实践>,其深入浅出的讲解,让我爱不释手.其中讲到了漏斗限流,在Redis中可以使用 Redis-Cell 模块来做基于Redis的 ...

  6. Java多线程:Semaphore

    自从5.0开始,jdk在java.util.concurrent包里提供了Semaphore 的官方实现. Java 5.0里新加了4个协调线程间进程的同步装置,它们分别是: Semaphore, C ...

  7. Java多线程-通讯方式

    Java多线程-通讯方式 线程之间为什么要通信? 通信的目的是为了更好的协作,线程无论是交替式执行,还是接力式执行,都需要进行通信告知.那么java线程是如何通信的呢,大致有以下六种方式. Java线 ...

  8. java服务限流_Java实现系统限流

    在微服务系统中,缓存.限流.熔断是保证系统高可用的三板斧,今天我们就来聊聊限流. 限流是保障系统高可用的方式之一,当然啦也是大厂高频面试题,如果阿里的面试官问一句:"如何实现每秒钟1K个请求 ...

  9. 【开发经验】java代码中实现限流

    限流目的 限流的目的是防止恶意请求流量.恶意攻击.或者防止流量超过系统峰值. 流量达到峰值时,会有一个熔断策略,常见的熔断策略: 直接拒绝请求,跳转到一个"服务器出小差"页面 排队 ...

最新文章

  1. 交叉验证分析每一折(fold of Kfold)验证数据的评估指标并绘制综合ROC曲线
  2. 「Excel技巧」Excel技巧之如何看文件里的宏?
  3. 有这么一群人,他们通过AI撬动世界!
  4. ubuntu右键在当前位置打开终端
  5. 欧洲顶级云数据中心着火,损失惨重!筑牢数据中心“防火墙”,可靠才是王道!...
  6. 银角大王 python_小猿圈python学习-细讲数据类型-列表
  7. 4.4.5 清除变量内容
  8. java sender_Spring Boot用JavaMailSender发送邮件方法
  9. 数据太大?你该了解Hadoop分布式文件系统
  10. Atitit webdav的使用与配置总结attilax总结 目录 1. 支持的协议 2 1.1. http File unc 2 2. 应用场景 2 2.1. 远程文件管理实现功能 文件建立
  11. Hibernate的org.hibernate.dialect.Oracle9Dialect错误
  12. php框架laravel构造者,Laravel框架的体系结构
  13. 2021年新安全生产法知识考试题库
  14. t3服务器一登录就运行时错误,用友T3软件登陆系统管理提示运行时错误3709
  15. 阿里巴巴的微服务开源之路
  16. HetConv--Heterogeneous-Kernel-Based-Convolutions-for-Deep-CNNs
  17. The Thirty-fourth Of Word-Day
  18. SampleGrabber开发问题与解决方案
  19. 银行家舍入-四舍六入五成双
  20. Android 设置空白背景Activity

热门文章

  1. 带你走进STM32世界,看看它能做些什么???
  2. Print2Flash的工作原理与入门使用
  3. WIN10使用右键从属性里复制的路径无效
  4. c和python哪个适合零基础_零基础到底应该如何入门学习C/C++语言,他是这么做的。...
  5. Python中集合set的使用详解
  6. 双色球76期精确打击
  7. 关于粒子群惯性权重的描述
  8. 白泽六足机器人_arduino_v1——零件准备
  9. 360杀毒属于计算机操作系统吗,win10要不要装杀毒软件_win10有必要安装360吗
  10. 如何挂载企业邮箱网盘到windows本地