coding++:Semaphore—RateLimiter-漏桶算法-令牌桶算法
java中对于生产者消费者模型,或者小米手机营销 1分钟卖多少台手机等都存在限流的思想在里面。
关于限流 目前存在两大类,从线程个数(jdk1.5 Semaphore)和RateLimiter速率(guava)
Semaphore:从线程个数限流
RateLimiter:从速率限流 目前常见的算法是漏桶算法和令牌算法
令牌桶算法。相比漏桶算法而言区别在于,令牌桶是会去匀速的生成令牌,拿到令牌才能够进行处理,类似于匀速往桶里放令牌
漏桶算法是:生产者消费者模型,生产者往木桶里生产数据,消费者按照定义的速度去消费数据
应用场景:
漏桶算法:必须读写分流的情况下,限制读取的速度
令牌桶算法:必须读写分离的情况下,限制写的速率或者小米手机饥饿营销的场景 只卖1分种抢购1000实现的方法都是一样。
RateLimiter来实现对于多线程问题查找时,很多时候可能使用的类都是原子性的,但是由于代码逻辑的问题,也可能发生线程安全问题
1、关于RateLimter和Semphore简单用法
package concurrent; import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.*;
import java.util.stream.IntStream; import static java.lang.Thread.currentThread; /**
* ${DESCRIPTION}
* 关于限流 目前存在两大类,从线程个数(jdk1.5 Semaphore)和RateLimiter速率(guava)
* Semaphore:从线程个数限流
* RateLimiter:从速率限流 目前常见的算法是漏桶算法和令牌算法,下面会具体介绍
*
* @author mengxp
* @version 1.0
* @create 2018-01-15 22:44
**/
public class RateLimiterExample { //Guava 0.5的意思是 1秒中0.5次的操作,2秒1次的操作 从速度来限流,从每秒中能够执行的次数来
private final static RateLimiter limiter=RateLimiter.create(0.5d); //同时只能有三个线程工作 Java1.5 从同时处理的线程个数来限流
private final static Semaphore sem=new Semaphore(3);
private static void testSemaphore(){
try {
sem.acquire();
System.out.println(currentThread().getName()+" is doing work...");
TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
sem.release();
System.out.println(currentThread().getName()+" release the semephore..other thread can get and do job");
}
} public static void runTestSemaphore(){
ExecutorService service = Executors.newFixedThreadPool(10);
IntStream.range(0,10).forEach((i)->{
//RateLimiterExample::testLimiter 这种写法是创建一个线程
service.submit(RateLimiterExample::testSemaphore);
});
} /**
* Guava的RateLimiter
*/
private static void testLimiter(){
System.out.println(currentThread().getName()+" waiting " +limiter.acquire());
} //Guava的RateLimiter
public static void runTestLimiter(){
ExecutorService service = Executors.newFixedThreadPool(10);
IntStream.range(0,10).forEach((i)->{
//RateLimiterExample::testLimiter 这种写法是创建一个线程
service.submit(RateLimiterExample::testLimiter);
});
} public static void main(String[] args) {
IntStream.range(0,10).forEach((a)-> System.out.println(a));//从0-9
//runTestLimiter();
runTestSemaphore();
}
}
2、实现漏桶算法
package concurrent.BucketAl; import com.google.common.util.concurrent.Monitor;
import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import static java.lang.Thread.currentThread; /**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-20 22:42
* 实现漏桶算法 实现多线程生产者消费者模型 限流
**/
public class Bucket {
//定义桶的大小
private final ConcurrentLinkedQueue<Integer> container=new ConcurrentLinkedQueue<>(); private final static int BUCKET_LIMIT=1000; //消费者 不论多少个线程,每秒最大的处理能力是1秒中执行10次
private final RateLimiter consumerRate=RateLimiter.create(10d); //往桶里面放数据时,确认没有超过桶的最大的容量
private Monitor offerMonitor=new Monitor(); //从桶里消费数据时,桶里必须存在数据
private Monitor consumerMonitor=new Monitor(); /**
* 往桶里面写数据
* @param data
*/
public void submit(Integer data){
if (offerMonitor.enterIf(offerMonitor.newGuard(()->container.size()<BUCKET_LIMIT))){
try {
container.offer(data);
System.out.println(currentThread()+" submit.."+data+" container size is :["+container.size()+"]");
} finally {
offerMonitor.leave();
}
}else {
//这里时候采用降级策略了。消费速度跟不上产生速度时,而且桶满了,抛出异常
//或者存入MQ DB等后续处理
throw new IllegalStateException(currentThread().getName()+"The bucket is ful..Pls latter can try...");
}
} /**
* 从桶里面消费数据
* @param consumer
*/
public void takeThenConsumer(Consumer<Integer> consumer){
if (consumerMonitor.enterIf(consumerMonitor.newGuard(()->!container.isEmpty()))){
try {
//不打印时 写 consumerRate.acquire();
System.out.println(currentThread()+" waiting"+consumerRate.acquire());
Integer data = container.poll();
//container.peek() 只是去取出来不会删掉
consumer.accept(data);
}finally {
consumerMonitor.leave();
}
}else {
//当木桶的消费完后,可以消费那些降级存入MQ或者DB里面的数据
System.out.println("will consumer Data from MQ...");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
2.1 漏桶算法测试类
package concurrent.BucketAl; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream; import static java.lang.Thread.currentThread; /**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-20 23:11
* 漏桶算法测试
* 实现漏桶算法 实现多线程生产者消费者模型 限流
**/
public class BuckerTest { public static void main(String[] args) {
final Bucket bucket = new Bucket();
final AtomicInteger DATA_CREATOR = new AtomicInteger(0); //生产线程 10个线程 每秒提交 50个数据 1/0.2s*10=50个
IntStream.range(0, 10).forEach(i -> {
new Thread(() -> {
for (; ; ) {
int data = DATA_CREATOR.incrementAndGet();
try {
bucket.submit(data);
TimeUnit.MILLISECONDS.sleep(200);
} catch (Exception e) {
//对submit时,如果桶满了可能会抛出异常
if (e instanceof IllegalStateException) {
System.out.println(e.getMessage());
//当满了后,生产线程就休眠1分钟
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
}).start();
}); //消费线程 采用RateLimiter每秒处理10个 综合的比率是5:1
IntStream.range(0, 10).forEach(i -> {
new Thread(
() -> {
for (; ; ) {
bucket.takeThenConsumer(x -> {
System.out.println(currentThread()+"C.." + x);
});
}
}
).start();
}); }
}
3、令牌桶算法
package concurrent.TokenBucket; import com.google.common.util.concurrent.RateLimiter; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import static java.lang.Thread.currentThread;
import static java.lang.Thread.interrupted; /**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-21 0:18
* 令牌桶算法。相比漏桶算法而言区别在于,令牌桶是会去匀速的生成令牌,拿到令牌才能够进行处理,类似于匀速往桶里放令牌
* 漏桶算法是:生产者消费者模型,生产者往木桶里生产数据,消费者按照定义的速度去消费数据
*
* 应用场景:
* 漏桶算法:必须读写分流的情况下,限制读取的速度
* 令牌桶算法:必须读写分离的情况下,限制写的速率或者小米手机饥饿营销的场景 只卖1分种抢购1000
*
* 实现的方法都是一样。RateLimiter来实现
* 对于多线程问题查找时,很多时候可能使用的类都是原子性的,但是由于代码逻辑的问题,也可能发生线程安全问题
**/
public class TokenBuck { //可以使用 AtomicInteger+容量 可以不用Queue实现
private AtomicInteger phoneNumbers=new AtomicInteger(0);
private RateLimiter rateLimiter=RateLimiter.create(20d);//一秒只能执行五次
//默认销售500台
private final static int DEFALUT_LIMIT=500;
private final int saleLimit; public TokenBuck(int saleLimit) {
this.saleLimit = saleLimit;
} public TokenBuck() {
this(DEFALUT_LIMIT);
} public int buy(){
//这个check 必须放在success里面做判断,不然会产生线程安全问题(业务引起)
//原因当phoneNumbers=99 时 同时存在三个线程进来。虽然phoneNumbers原子性,但是也会发生。如果必须写在这里,在success
//里面也需要加上double check
/* if (phoneNumbers.get()>=saleLimit){
throw new IllegalStateException("Phone has been sale "+saleLimit+" can not buy more...")
}*/ //目前设置超时时间,10秒内没有抢到就抛出异常
//这里的TimeOut*Ratelimiter=总数 这里的超时就是让别人抢几秒,所以设置总数也可以由这里的超时和RateLimiter来计算
boolean success = rateLimiter.tryAcquire(10, TimeUnit.SECONDS);
if (success){
if (phoneNumbers.get()>=saleLimit){
throw new IllegalStateException("Phone has been sale "+saleLimit+" can not buy more...");
}
int phoneNo = phoneNumbers.getAndIncrement();
System.out.println(currentThread()+" user has get :["+phoneNo+"]");
return phoneNo;
}else {
//超时后 同一时间,很大的流量来强时,超时快速失败。
throw new RuntimeException(currentThread()+"has timeOut can try again...");
} }
}
3.1、令牌桶算法的测试类
package concurrent.TokenBucket; import java.util.stream.IntStream; /**
* ${DESCRIPTION}
*
* @author mengxp
* @version 1.0
* @create 2018-01-21 0:40
**/
public class TokenBuckTest {
public static void main(String[] args) {
final TokenBuck tokenBuck=new TokenBuck(200); IntStream.range(0,300).forEach(i->{
//目前测试时,让一个线程抢一次,不用循环抢
//tokenBuck::buy 这种方式 产生一个Runnable
new Thread(tokenBuck::buy).start();
});
}
}
coding++:Semaphore—RateLimiter-漏桶算法-令牌桶算法的更多相关文章
- 漏桶、令牌桶限流的Go语言实现
限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数. 我们生活中也会经常遇到限流的场景,比如:某景区限制每日进入景区的游客数量为8万人:沙河地铁站早高峰通过站外排队逐一放行的方式限制同 ...
- coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介
RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...
- 使用Redis实现令牌桶算法
在限流算法中有一种令牌桶算法,该算法可以应对短暂的突发流量,这对于现实环境中流量不怎么均匀的情况特别有用,不会频繁的触发限流,对调用方比较友好. 例如,当前限制10qps,大多数情况下不会超过此数量, ...
- 【springcloud】2.eureka源码分析之令牌桶-限流算法
国际惯例原理图 代码实现 package Thread; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomi ...
- Redis令牌桶限流
一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...
- 令牌桶限流思路分享(PHP+Redis实现机制)
一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...
- CIR,CBS,EBS,PIR,PBS傻傻分不清楚?看这里!—-揭秘令牌桶
概述 春暖花开的时候,大家都开着汽车外出旅游欣赏美丽的风景,却被堵在高速公路上,你是否为此感到痛苦?但如果有一种机制可以评估高速公路上的车流量.控制车流情况,确保进入高速公路的汽车都能在路上安全畅行, ...
- 基于.net的分布式系统限流组件(限流算法:令牌算法和漏斗算法)
转载链接:https://www.cnblogs.com/vveiliang/p/9049393.html 1.令牌桶算法 令牌桶算法是比较常见的限流算法之一,大概描述如下: 1).所有的请求在处理之 ...
- 限流之令牌桶算法——RateLimiter官方文档
原文链接 作者:Dimitris Andreou 译者:魏嘉鹏 校对:方腾飞 RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证.如果必要的话,每个acquire() 会阻 ...
随机推荐
- Java入门教程八(面向对象)
对象概念 一切皆是对象.把现实世界中的对象抽象地体现在编程世界中,一个对象代表了某个具体的操作.一个个对象最终组成了完整的程序设计,这些对象可以是独立存在的,也可以是从别的对象继承过来的.对象之间通过 ...
- python 保存两位小数
一.代码 import decimal decimal.getcontext().rounding = decimal.ROUND_HALF_UP def index(number): n = str ...
- 前端每日实战:132# 视频演示如何用纯 CSS 创作一只思考的手
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/WgdVyx/ 可交互视频 此视频是 ...
- 前端每日实战:10# 视频演示如何用纯 CSS 创作一个同心圆弧旋转 loader 特效
效果预览 按下右侧的"点击预览"按钮在当前页面预览,点击链接全屏预览. https://codepen.io/zhang-ou/pen/OZmXQX 可交互视频教程 此视频是可以交 ...
- python数据转换
主要内容 1:数字类型:算术运算 bool:判断真假,运用场景在逻辑运算里较多,比如while循环了. 字符串:可以索引取值,可以嵌套 列表:存放任意数据类型,因为是按序存放的,故可以索引取值, 字典 ...
- 蓝牙技术 A2DP AVRCP BlueZ
BlueZ 做为 linux 标准的协议栈,提供非常多的 profile ,各种的支持,ble , 蓝牙网络,文件传输,a2dp 音频传输. A2DP——Advanced Audio Distribu ...
- centOS 6.5 yum升级 gcc4.8 然后又退回来4.4
CentOS 6.5 用了很多年了,一直舍不得省7 . 由于要用到 c++ 11 ,所以决定升级一下. 为了省事我选择用 yum 方式升级,结果最后还是不能用,差点搞坏,这是真机,重装麻烦了. get ...
- Java自学路线图之Java框架自学
Java自学路线图的框架分为两个阶段,第一阶段的Java框架包含六个内容:MyBatis,Spring,SpringMVC,Maven高级,Git,Dubbo. 在Java自学过程中掌握框架的使用,对 ...
- CSS核心概念之盒子模型
盒子模型(Box Model) 关于更多CSS核心概念的文章请关注GitHub--CSS核心概念. 当对一个文档进行布局的时候,浏览器的渲染引擎会根据标准之一的 CSS 基础框盒模型(CSS basi ...
- css中:link和@import的区别
两者都是外部引用css的方式.但是有一定的区别: 1. 从属关系:link是一个xhtml标签,除了加载css外,还可以定义 RSS.rel 连接属性等: @import属于css范畴,只能加载css ...