当前位置: 首页 > news >正文

使用CountdownLatch和线程池批量处理http请求,并处理响应数据

背景和问题

​ 背景:最近项目的一个接口数据,需要去请求其他多个服务器的数据,然后统一返回;
问题点:如果遍历所有的服务器地址,然后串行请求就会出现请求时间过长,加入需要请求十个服务器,一个服务器是1s那么请求服务器数据总时间就需要10s,导致响应时间太长,所以需要使用多线程。如果直接使用多线程去请求,那么没法知道是否所有接口是否都请求结束,所以用到了技术门闩CountdownLatch,每一个接口请求结束之后都会调用CountdownLatchcount方法进行计数,当归零后就会唤醒主线程进行后续逻辑,并且使用ConcurrentLinkedQueue记录响应结果。

话不多说,直接上代码!!

准备数据:

​ 四个接口(三个模拟请求服务器接口,一个直接访问的接口),由于我是本地环境,所以在每个接口中设置了不同的休眠时间,来模拟不同服务器场景

代码展示

  1. 模拟接口

    	@RequestMapping("/hello")public String hello(@RequestParam(value = "id") Long id, @RequestBody User params) {if (id != 1) {return null;}System.out.println(params.toString());try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}List<User> users = new ArrayList<>();users.add(new User("张三", 1, "男"));users.add(new User("李四", 2, "男"));users.add(new User("王五", 3, "女"));return JSON.toJSONString(users);}@RequestMapping("/hello1")public String hello1(@RequestParam(value = "id") Long id) {if (id != 2) {return null;}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}List<User> users = new ArrayList<>();users.add(new User("张三1", 11, "男"));users.add(new User("李四1", 21, "男"));users.add(new User("王五1", 31, "女"));return JSON.toJSONString(users);}@RequestMapping("/hello2")public String hello2(@RequestParam(value = "id") Long id) {if (id != 3) {return null;}try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}List<User> users = new ArrayList<>();users.add(new User("张三2", 12, "男"));users.add(new User("李四2", 22, "男"));users.add(new User("王五2", 32, "女"));return JSON.toJSONString(users);}	
    
  2. 直接访问接口数据

     @RequestMapping("/demo")public String demo() throws InterruptedException, IOException {OkHttpClient client = new OkHttpClient();final CountDownLatch countDownLatch = new CountDownLatch(3);// 使用ConcurrentLinkedQueue 存储每个请求的响应结果,ConcurrentLinkedQueue 是一个线程安全的final ConcurrentLinkedQueue<Response> responses = new ConcurrentLinkedQueue<>();ExecutorService executor = Executors.newFixedThreadPool(10);long start = System.currentTimeMillis();for (int i = 1; i <= urls.size(); i++) {String url = urls.get(i - 1);int finalI = i;executor.submit(() -> {//构建请求中需要的请求参数 id 通过 RequestParam获取HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();urlBuilder.addQueryParameter("id", String.valueOf(finalI));String newUrl = urlBuilder.build().toString();// 表单提交
    //                FormBody formBody = new FormBody.Builder().add("id", String.valueOf(finalI)).build();
    //                Request request = new Request.Builder().url(newUrl).post(formBody).build();// 构建参数,通过@RequestBody取出参数User user = new User("1", 2, "男");okhttp3.RequestBody requestBody = okhttp3.RequestBody.create(MediaType.parse("application/json; charset=utf-8"),JSON.toJSONString(user));Request request = new Request.Builder().url(newUrl).post(requestBody).build();try {Response response = client.newCall(request).execute();if (!response.isSuccessful()) {// 可以在单独记录下,然后做异常处理throw new IOException("请求失败:" + response);} else {responses.add(response);}} catch (IOException e) {throw new RuntimeException(e);} finally {// 执行一个请求进行一次计数countDownLatch.countDown();}});}//等待countDownlatch 计数门闩归零即所有线程请求完成,然后唤醒线程,但是会设置一个最长等待时长 10sboolean await = countDownLatch.await(10, TimeUnit.SECONDS);executor.shutdown();long end = System.currentTimeMillis();System.out.println("http的整个请求时间为:" + DateUtil.formatBetween(end - start));Map<String,  List<User>> res = new HashMap<>();if (!responses.isEmpty()) {int i = 0;for (Response response : responses) {URL url = response.request().url().url();String string = response.body().string();List<User> users = JSON.parseArray(string, User.class);res.put(url.toString(),users);}} else {System.out.println("无响应结果!");}System.out.println(res);return "demo";}
    
  3. 其他相关信息

      private static final List<String> urls = new ArrayList<>();static {urls.add("http://localhost:8080/hello");urls.add("http://localhost:8080/hello1");urls.add("http://localhost:8080/hello2");}public static class User {private String name;private Integer age;private String sex;public User(String name, Integer age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
    
            //相关依赖<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.21</version></dependency><!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>3.5.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.38</version></dependency>
    

结果

在这里插入图片描述

结果解释

  1. 第一行:是/hello接口中@RequestBody的参数打印。
  2. 第二行是整个请求时间,因为我设置的/hello2接口时间为5s,可以看到这里的接口请求时间是最长的接口时间,而不是所有时间相加。
  3. 可以看到设置的参数能够成功获取,并且数据能成功接收。

注意事项

在这里插入图片描述

  1. response中body体的数据只能取一次,取出之后就会将其设置为closed,所以建议使用变量进行接收之后再做处理。

  2. 这个唤醒时间最好设置一个默认值,免得程序出问题主线程一直卡死在这里。

    countDownLatch.await(10, TimeUnit.SECONDS);
    
  3. 这个count一定不能忘了,不然这个主线程也就卡死了

在这里插入图片描述

最后,这只是一个简单的demo程序,真实的项目情况肯定是不一样的,所以只能做一个参考,具体情况还需做具体处理!

源码已提交gitee

相关文章:

使用CountdownLatch和线程池批量处理http请求,并处理响应数据

背景和问题 ​ 背景&#xff1a;最近项目的一个接口数据&#xff0c;需要去请求其他多个服务器的数据&#xff0c;然后统一返回&#xff1b; 问题点&#xff1a;如果遍历所有的服务器地址&#xff0c;然后串行请求就会出现请求时间过长&#xff0c;加入需要请求十个服务器&…...

记录--怎么写一个可以鼠标控制旋转的div?

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 说在前面 鼠标控制元素旋转在现在也是一个很常见的功能&#xff0c;让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。 效果展示 体验地址 code.juejin.cn/pen/7290719… 实现…...

JVM第十八讲:调试排错 - Java 问题排查之工具单

调试排错 - Java 问题排查之工具单 程序员想要有更好的发展&#xff0c;排查问题的能力一定得加强。举个例子&#xff1a;cpu100% 怎么排查&#xff0c;线上接口逐渐变慢了该怎么排查&#xff1f;慢查询该如何治理&#xff1f;你的思路是啥&#xff1f;本文是JVM第十八讲&#…...

JAVA基础-正则表达式(12)

目录 Java 正则表达式正则表达式实例正则表达式语法 Matcher 类的方法索引方法查找方法替换方法start 和 end 方法 Java 正则表达式 正则表达式定义了字符串的模式。 正则表达式可以用来搜索、编辑或处理文本。 正则表达式并不仅限于某一种语言&#xff0c;但是在每种语言中有细…...

[论文笔记]GPT-1

引言 今天带来论文Improving Language Understanding by Generative Pre-Training的笔记,它的中文题目为:通过生成式预训练改进语言理解。其实就是GPT的论文。 自然语言理解可以应用于大量NLP任务上,比如文本蕴含、问答、语义相似和文档分类。虽然无标签文本语料是丰富的,…...

【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割1(综述篇)

在上一个关于3D 目标的任务&#xff0c;是基于普通CNN网络的3D分类任务。在这个任务中&#xff0c;分类数据采用的是CT结节的LIDC-IDRI数据集&#xff0c;其中对结节的良恶性、毛刺、分叶征等等特征进行了各自的等级分类。感兴趣的可以直接点击下方的链接&#xff0c;直达学习&…...

css之Flex弹性布局

文章目录 &#x1f415;前言&#xff1a;&#x1f3e8;定义flex容器 display:flex&#x1f3e8;在flex容器中子组件进行排列&#x1fa82;行排列 flex-direction: row&#x1fa82;将行排列进行翻转排列 flex-direction: row-reverse&#x1f3c5;按列排列 flex-direction: col…...

web.xml配置详解

在Java Web应用程序中&#xff0c;web.xml是一个XML配置文件&#xff0c;用于定义和配置Servlet、过滤器、监听器和其他Web应用程序组件的行为和属性。web.xml文件通常位于Web应用程序的WEB-INF目录下&#xff0c;用于描述Web应用程序的部署信息和配置。以下是一些web.xml配置的…...

关于我学习Go语言在CSDN分享的心得体会

最近我一直在学习Go语言&#xff0c;并通过CSDN平台分享我的学习心得和体会。在这篇博客中&#xff0c;我将与大家分享我在学习Go语言过程中的经验和收获。希望通过这篇博客能够帮助其他Go语言初学者更好地掌握这门语言&#xff0c;并与广大Go语言爱好者进行交流和互动。 选择…...

Java类的Builder应用以及使用@Data和@Builder高效应用Builder

⭐Java Builder模式&#xff1a;是Java设计模式之一&#xff0c;它属于对象创建型模式&#xff0c;是将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 结论一&#xff1a;使用lombok的Data和Builder注解构建Java类的Builder简洁高效&am…...

【Qt控件之QTabWidget】介绍及使用

描述 QTabWidget类提供了一个带有选项卡的小部件堆栈。 选项卡小部件提供了一个选项卡栏&#xff08;参见QTabBar&#xff09;和一个“页面区域”&#xff0c;用于显示与每个选项卡相关联的页面。默认情况下&#xff0c;选项卡栏显示在页面区域的上方&#xff0c;但可以使用…...

Linux实战——网络连接模式的三种模式

Linux可以分为三种网络模式&#xff1a; 桥接模式 &#xff08;vmnet0) 仅主机模式 (vmnet1) NAT模式 (vmnet8) 当我们下载了vmware之后&#xff0c;在电脑会出现两个虚拟网卡&#xff0c;VMware Network Adapter VMnet1、VMware Network Adapter VMnet8。 可以通过查找 控…...

嵌入式实时操作系统的设计与开发(任意大小的内存管理)

任意大小的内存管理是根据用户需要为其分配内存&#xff0c;即用户需要多大内存就通过acoral_malloc2()为之分配多大内存&#xff0c;同时每块分配出去的内存前面都有一个控制块&#xff0c;控制块里记录了该块内存的大小。 同时未分配出去的内存也有一个控制块&#xff0c;寻…...

文件读取结束的判定

大家好啊&#xff0c;我们今天来补充文件操作的读取结束的判定。 被错误使用的feof 牢记&#xff1a;在文件读取过程中&#xff0c;不能用feof函数的返回值直接用来判断文件的是否结束而是应用于当文件读取结束的时候&#xff0c;判断是读取失败结束&#xff0c;还是遇到文件尾…...

《基于 Vue 组件库 的 Webpack5 配置》9.module.exports 可为数组类型且注意编译顺序

module.exports常见是对象类型&#xff0c;其实也可用数组类型&#xff1b;注意编译顺序&#xff0c;从后往前 编&#xff1a; 也就是说先编 another.js&#xff0c;再编 index.js&#xff1b;所以代码第 9 行不能设置为 true&#xff0c;仅在第一次&#xff0c;也就是代码第19…...

​CUDA学习笔记(四)device管理

本篇博文转载于https://www.cnblogs.com/1024incn/tag/CUDA/&#xff0c;仅用于学习。 device管理 NVIDIA提供了集中凡是来查询和管理GPU device&#xff0c;掌握GPU信息查询很重要&#xff0c;因为这可以帮助你设置kernel的执行配置。 本博文将主要介绍下面两方面内容&…...

【算法练习Day25】 重新安排行程N 皇后 解数独

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 重新安排行程N 皇后解数独总…...

软考-访问控制技术原理与应用

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 by 2023年10月 访问控制概念 访问控制是计算机安全的一个重要组成部分&#xff0c;用于控制用户或程序如…...

优测云测试平台 | 有效的单元测试

一、前言 本文作者提出了一种评价单元测试用例的质量的思路&#xff0c;即判断用例是否达到测试的“四大目标”。掌握识别好的用例的能力&#xff0c;可以帮助我们高效地写出高质量的测试用例。 评判冰箱的好坏&#xff0c;并不需要有制造一台冰箱的能力。在开始写测试用例之…...

Java设计模式之外观模式

定义 又名门面模式&#xff0c;是一种通过为多个复杂的子系统提供一个一致的接口&#xff0c;而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口&#xff0c;外部应用程序不用关心内部子系统的具体的细节&#xff0c;这样会大大降低应用程序的复杂度&#xff0c;…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...