前言

RPC 服务中,每个服务的容量都是有限的,即资源有限,只能承受住给定的网络请求,所以,在设计 RPC 框架的时候,一定要考虑流量控制这个问题。而 Java 中,实现流量控制有很多中方式,今天说 2 种。

Semaphore 实现流控

代码:

  static Semaphore semaphore = new Semaphore(100);

  public static void main(String[] args) {

    Executor timeTask = Executors.newScheduledThreadPool(1);
((ScheduledExecutorService) timeTask).scheduleAtFixedRate(
() -> semaphore.release(100 - semaphore.availablePermits()), 1000, 1000,
TimeUnit.MILLISECONDS); Executor pool = Executors.newFixedThreadPool(100); for (int i = 0; i < 100; i++) {
final int num = i;
pool.execute(() -> {
for (; ; ) {
for (int j = 0; j < 200; j++) {
if (semaphore.tryAcquire()) {
callRpc(num, j);
} else {
System.err.println("call fail");
}
}
}
});
}
} private static void callRpc(int num, int j) {
System.out.println(String.format("%s - %s: %d %d", new Date(), Thread.currentThread(), num, j));
}

代码中,我们模拟了 100 个线程,每个线程无限调用 RPC。

同时使用另一个定时任务,定时更新 Semaphore 可用许可为 100。

客户端线程调用时,会尝试获取信号量,当获取成功时,才会调用调用 RPC,反之,打印失败。

这个小程序实现了每秒钟限制 100 个请求的 RPC 的流量控制。

AtomicInteger 实现流控

代码:

  static AtomicInteger count = new AtomicInteger();

  public static void main(String[] args) {
Executor timeTask = Executors.newScheduledThreadPool(1);
((ScheduledExecutorService) timeTask).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
count.getAndSet(100);
}
}, 1000, 1000, TimeUnit.MILLISECONDS); Executor pool = Executors.newFixedThreadPool(100); for (int i = 0; i < 100; i++) {
final int num = i;
pool.execute(() -> {
for (; ; ) {
for (int j = 0; j < 200; j++) {
if (count.get() >= 0) {// 快速判断,否则大量的 CAS 操作将会定时任务更新计数器 count
if (count.decrementAndGet() >= 0) {
callRpc(num, j);
}
}
}
}
});
}
} private static void callRpc(int num, int j) {
System.out.println(String.format("%s - %s: %d %d", new Date(), Thread.currentThread(), num, j));
}

这段代码和上面的类似,只是使用的 API 不同,这里使用的是 CAS。通过对 CAS 递减,达到流控的目的。

注意,这里有一个双重判断,先判断 count.get() >= 0,为什么呢?

如果直接使用 decrementAndGet 方法,则会使用 CAS,100 个线程并发使用 CAS ,将会导致定时任务的 CAS 操作不够及时。

所以,先判断,是否小于0 ,如果小于0了,就不必尝试 CAS,避免影响定时任务。

使用并发工具实现 RPC 调用流量控制的更多相关文章

  1. 《精通并发与Netty》学习笔记(07 - 基于Thrift实现Java与Python的RPC调用)

    上节我们介绍了基于Thrift实现java与java的RPC调用,本节我们基于Thrift实现Java与Python的RPC调用 首先,修改data.thirft文件,将命名空间由java改为py n ...

  2. java中的并发工具类

    在jdk的并发包里提供了几个非常有用的并发工具类.CountDownLatdch.CyclicBarrier和Semaphore工具类提供了一种并发流程控制的手段,Exchanger工具类则提供了在线 ...

  3. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  4. Java中的并发工具类(CountDownLatch、CyclicBarrier、Semaphore、Exchanger)

    在JDK的并发包里提供了很多有意思的并发工具类.CountDownLatch.CyclicBarrier和Semaphore 工具类提供了一种并发流程控制的手段,Exchanger 工具类则提供了在线 ...

  5. 并发工具类(三)控制并发线程的数量 Semphore

    前言   JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...

  6. 基于AQS实现的Java并发工具类

    本文主要介绍一下基于AQS实现的Java并发工具类的作用,然后简单谈一下该工具类的实现原理.其实都是AQS的相关知识,只不过在AQS上包装了一下而已.本文也是基于您在有AQS的相关知识基础上,进行讲解 ...

  7. 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger

    1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...

  8. java并发之并发工具

    在JDK的并发包里提供了几个非常有用的并发工具类.CountDownLatch.CyclicBarrier和Semaphore工具类提供了一种并发流程控制的手段,Exchanger工具类则提供了在线程 ...

  9. Java 并发系列之八:java 并发工具(4个)

    1. CountDownLatch 2. CyclicBarrier 3. Semaphore 4. Exchanger 5. txt java 并发工具 通俗理解 CountDownLatch 等A ...

随机推荐

  1. AngularJS 模块及provide

    一.模块 模块是一些功能的集合,如控制器.服务.过滤器.指令等子元素组成的整体. 1.注册和使用 模块相当于是一个注册表,保存着名字和编程元素的对照表,可存入也可取出. angular.module( ...

  2. Nvu

    在Jennifer Niederst Robbins的书<Learning Web design>(密码:v9i1)推荐软件Nvu 界面: Nvu tips:

  3. inline&friend&操作符重载

    (1).inline:是一种以空间换时间的做法省去调用函数的额外开销,提高程序的运行效率,它对于编译器而言只是一种建议 (2).友元函数:是可以直接访问类的private成员的非成员函数.它是定义在类 ...

  4. unigui结合JS方法

    在js中界面上所有组件都当成html里来控制 1.控制按钮事件 document.getElementById(MainForm.UniButton4.getId()).click(); 这个方法让J ...

  5. 【图数据结构的遍历】java实现广度优先和深度优先遍历

    [图数据结构的遍历]java实现广度优先和深度优先遍历 宽度优先搜索(BFS)遍历图需要使用队列queue数据结构: 深度优先搜索(DFS, Depth First Search)的实现 需要使用到栈 ...

  6. atom编辑器社区插件推荐

    atom是github出品的文本编辑器,为开发者又提供了一款易用.牛逼的文本编译器.在开始接触前端并从工作开始一直用webstrom来进行前端开发,开始使用时,被他各种强大神奇的功能给折服:支持zen ...

  7. 【新手向】阿里云上ubuntu+flask+gunicorn+nginx服务器部署(二)项目部署

    本项目实现的是类似于ins的图片分享网站.继续(一),当nginx的配置已修改好后,要在远程服务器上部署网站,只需要几个步骤: 1 前期准备 2 将运行网站的代码从github上下载过来 3 下载依赖 ...

  8. Swift5 语言参考(九) 泛型和参数

    本章介绍泛型类型,函数和初始值设定项的参数和参数.声明泛型类型,函数,下标或初始化程序时,可以指定泛型类型,函数或初始化程序可以使用的类型参数.当创建泛型类型的实例或调用泛型函数或初始化程序时,这些类 ...

  9. gulp 打包错误 TypeError: Path must be string. Received undefined

    Running gulp gives “path.js:7 throw new TypeError('Path must be a string. Received ' + inspect(path) ...

  10. flask框架--模板

    今天又是一个精彩又无聊的一天,不过随着知识的缓慢的增加我的内心也充满了干劲,虽然前进的有些缓慢 但我不会这么容易放弃的,一定要相信自己,不要灰心 好了 ~ 不说废话了 , 我自己听的都有些受不了了 . ...