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-漏桶算法-令牌桶算法的更多相关文章

  1. 漏桶、令牌桶限流的Go语言实现

    限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数. 我们生活中也会经常遇到限流的场景,比如:某景区限制每日进入景区的游客数量为8万人:沙河地铁站早高峰通过站外排队逐一放行的方式限制同 ...

  2. coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介

    RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...

  3. 使用Redis实现令牌桶算法

    在限流算法中有一种令牌桶算法,该算法可以应对短暂的突发流量,这对于现实环境中流量不怎么均匀的情况特别有用,不会频繁的触发限流,对调用方比较友好. 例如,当前限制10qps,大多数情况下不会超过此数量, ...

  4. 【springcloud】2.eureka源码分析之令牌桶-限流算法

    国际惯例原理图 代码实现 package Thread; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomi ...

  5. Redis令牌桶限流

    一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...

  6. 令牌桶限流思路分享(PHP+Redis实现机制)

    一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...

  7. CIR,CBS,EBS,PIR,PBS傻傻分不清楚?看这里!—-揭秘令牌桶

    概述 春暖花开的时候,大家都开着汽车外出旅游欣赏美丽的风景,却被堵在高速公路上,你是否为此感到痛苦?但如果有一种机制可以评估高速公路上的车流量.控制车流情况,确保进入高速公路的汽车都能在路上安全畅行, ...

  8. 基于.net的分布式系统限流组件(限流算法:令牌算法和漏斗算法)

    转载链接:https://www.cnblogs.com/vveiliang/p/9049393.html 1.令牌桶算法 令牌桶算法是比较常见的限流算法之一,大概描述如下: 1).所有的请求在处理之 ...

  9. 限流之令牌桶算法——RateLimiter官方文档

    原文链接 作者:Dimitris Andreou  译者:魏嘉鹏 校对:方腾飞 RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证.如果必要的话,每个acquire() 会阻 ...

随机推荐

  1. Centos 7 中 部署 asp.net core 3.0 + nginx + mongodb 的一些新手简单入门,非docker

    目录 零.准备工作 一.部署Mongodb 1.安装Mongodb 2.创建mongodb的数据目录 3.设置目录权限 4.设置mongodb启动 5.修改mongodb的配置文件 6.启动Mongo ...

  2. [译]HTML&CSS Lesson7: 设置背景和渐变色

    背景对网站的设计有重大的影响.它有利于建立网站的整体感觉,设置分组,分配优先级,对网站的可用性也有相当大的影响. 在CSS中,元素的背景可以是一个纯色,一张图,一个渐变色或者它们的组合.在我们决定如何 ...

  3. 前端面试题-HTML语义化标签

    一.HTML5语义化标签 标签 描述 <article> 页面独立的内容区域. <aside> 页面的侧边栏内容. <bdi> 允许您设置一段文本,使其脱离其父元素 ...

  4. JAVA Integer值的范围

    原文出处:http://hi.baidu.com/eduask%C9%BD%C8%AA/blog/item/227bf4d81c71ebf538012f53.html package com.test ...

  5. PySide2的This application failed to start because no Qt platform plugin could be initialized解决方式

    解决PySide2的This application failed to start because no Qt platform plugin could be initialized问题 今天在装 ...

  6. 用vue-cli进行npm run dev时候Cannot GET/

    在用vue cli进行项目npm run dev 时候,页面Cannot GET/ 主要是把config/index.js里面的dev:{assetsPublicPath:'/'}改成了跟build里 ...

  7. iOS开发 - 设立UIButton的Image为Aspect Fit

    Button setImage设置的图片默认是会拉伸缩放的,如果我想要Aspect Fit的效果,要如何做呢?一开始我想到了用contentMode属性,很可惜不起作用.后来我发现button有一个i ...

  8. nlogn的最长不下降子序列【tyvj1254挑选士兵】

    var a,d:Array[-..]of longint; i,n,m,k,l:longint; function erfen(x:longint):longint; var mid,h,t:long ...

  9. Natas1 Writeup(查看页面源码)

    Natas2: 提示密码就在本页,但右键被禁用,可以使用F12或者抓包查看元素得到flag. flag:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi 常用的查看源码方法:右键查看. ...

  10. uni-app 遮罩模板

    1. common新建mask.vue文件. <template> <view> <view class="cpt-mask"> </vi ...