使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/115128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决谷歌学术bib信息不全的问题

在我们撰写学术论文时&#xff0c;经常需要引用参考文献。如果用latex撰写论文&#xff0c;势必会用到文献的bib信息&#xff0c;大部分的教程都会告诉我们去google scholar上去搜索。 一、问题描述 搜索一篇文章&#xff0c;然后选择cite&#xff0c;再选择bib。 很明显&…

固件签名的安全解决方案 安当加密

在汽车行业中&#xff0c;加密机常用于对固件进行签名&#xff0c;以增加固件的安全性和完整性。以下是几个可能的使用场景&#xff1a; 固件验证&#xff1a;当汽车制造商或供应商需要对固件进行验证时&#xff0c;可以使用加密机来验证固件的来源和完整性。通过使用公钥和私…

Node学习笔记之MySQL基本使用

使用 SQL 管理数据库 其实写接口简单来说就是操作数据库数据&#xff0c;所以我们需要学会数据库的增、删、查、改等基本操作 1. 什么是 SQL SQL&#xff08;英文全称&#xff1a;Structured Query Language&#xff09;是结构化查询语言&#xff0c;专门用来访问和处理数据…

面试题 02.02 返回倒数第 k 个节点

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 双指针。首先&#xff0c;让 head 指向 链表头节点&#xff0c;让 end 指向第 k 个节点。当end 非空时&…

从0到1:云计算工程师入门指南

华为职业认证覆盖ICT全领域&#xff0c;致力于提供领先的人才培养体系和认证标准培养数字化时代的新型ICT人才&#xff0c;构建良性的ICT人才生态。 华为推荐职业认证进阶路线 根据ICT从业者的学习和进阶需求华为职业认证分为工程师级别、高级工程师级别和专家级别三个认证等…

(2)Nmap

笔记目录 渗透测试工具(1)wireshark渗透测试工具(2)Nmap渗透测试工具(3)BurpsuiteAWD比赛(1)AWD入门攻略大纲 1.工具简介 (1)定义 ①功能 网络扫描和嗅探工具包&#xff0c;三个主要基本功能&#xff1a; 探测一组主机是否在线 扫描主机端口、嗅探所提供的网络服务 推断出主…

Keil实现Flash升级跳转(STM32/GD32/HC32)

编写BOOT程序&#xff0c;和APP程序。 BOOT程序检查OTA参数&#xff0c;执行OTA升级&#xff0c;然后跳转到APP代码。 记录一下跳转APP需要修改得东西&#xff1a; 1、BOOT程序 修改跳转地址 先检查APP地址是否有效 然后关闭外设 反初始化 设置MSP指针&#xff0c;进行跳转 …

ZooKeeper+HBase分布式集群环境搭建

安装版本&#xff1a;hadoop-2.10.1、zookeeper-3.4.12、hbase-2.3.1 一、zookeeper集群搭建与配置 1.下载zookeeper安装包 2.解压移动zookeeper 3.修改配置文件&#xff08;创建文件夹&#xff09; 4.进入conf/ 5.修改zoo.cfg文件 6.进入/usr/local/zookeeper-3.4.12/zkdata…

Vue 模板字符串碰到script无法识别,报错Parsing error: Unterminated template.

需求&#xff1a; 将js代码完整的显示在界面上&#xff0c;包括标签 代码如下&#xff1a; 报错信息如下&#xff1a; 我们在上图中可以看到模板字符串加入了script标签后会报错 原因&#xff1a;运行JS的时候由上至下&#xff0c;先识别模板字符串里面的script标签&#xf…

基于B/S架构,包括PC后台管理端、APP移动端、可视化大屏端的智慧工地源码

智慧工地管理平台充分运用数字化技术&#xff0c;聚焦施工现场岗位一线&#xff0c;依托物联网、互联网、AI等技术&#xff0c;围绕施工现场管理的人、机、料、法、环五大维度&#xff0c;以及施工过程管理的进度、质量、安全三大体系为基础应用&#xff0c;实现全面高效的工程…

计算机网络,网络(OSI)七层模型,三次握手四次挥手,get与post请求区别,网络IO(BIO\NIO\AIO),TCP与UDP区别

1.OSI模型&#xff1f; 开放式系统互联通信参考模型(Open System Interconnection Reference Model) OSI网络七层模型&#xff1a;应用层、表示层、会话层、传输层、网络层、数据链路层、物理层 TCP/IP协议群简化了OSI七层模型&#xff1a;应用层、传输层、网络层、数据链路…

自然语言处理---文本预处理概述

自然语言处理&#xff08;Natural Language Processing&#xff0c;简称NLP&#xff09;是计算机科学与语言学中关注于计算机与人类语言间转换的领域。其主要应用于&#xff1a;语音助手、机器翻译、搜索引擎、智能问答等。 文本预处理概述 文本语料在输送给模型前一般需要一…

QSlider 类使用教程

文章目录 1、简介2 、公共类型3、属性4、functions4.1、访问属性相关 function4.2、公共槽4.3、Signal4.4、其他方法 5、设置样式 QT 官方文档参考地址&#xff1a;https://doc.qt.io/qt-5/qslider.html 1、简介 QSlider是垂直或水平滑块条控件&#xff0c;最常见的应用就是视…

业绩不俗,毛利率下滑,股价接连下跌,片仔癀将向何处去?

撰稿|行星 来源|贝多财经 10月16日&#xff0c;中药龙头企业漳州片仔癀药业股份有限公司&#xff08;600436.SH&#xff0c;下称“片仔癀”&#xff09;发布截至9月30日的2023年前三季度业绩报告。发布财报后&#xff0c;片仔癀的股价多日下跌。 10月17日、18日、19日和20日…

探索流视频的发送

1.网络连接 2.主设备将某处视频开始的视频数据发送给从设备。 之前有读取本地视频并播放的demo,所以可以先测试网络连接的问题。 先用模拟器进行模拟吧。方便进行测试。 是的&#xff0c;可以使用Android设备使用上述库或框架来构建实时Web应用程序。虽然这些库和框架在Java服…

MySQL常见面试题

一、存储引擎相关 &#xff08;1&#xff09;MySQL 支持哪些存储引擎? MySQL支持多种存储引擎&#xff0c;比如InnoDB&#xff0c;MyISAM&#xff0c; MySQL大于等于5.5之后&#xff0c;默认存储引擎是InnoDB &#xff08;2&#xff09;InnoDB 和 MyISAM 有什么区别? InnoD…

【计算机网络】IP协议的相关特性

IP协议&#xff1a;互联网的核心组件 在当今高度数字化的世界中&#xff0c;互联网已成为人们生活、工作不可或缺的一部分。而在这个庞大的网络中&#xff0c;IP协议&#xff08;Internet Protocol&#xff09;作为核心的通信协议&#xff0c;发挥着至关重要的作用。本文将详细…

【二级建造师】首次报考人员需提供以下材料

(1)相应的学历证书原件及复印件; (2)本人身份证(或军官证)原件及复印件; (3)有效的业务工作证明(在报名表"单位意见"栏填写并加盖公章); (4)本人近期1寸同底免冠照片2张, 2寸同底免冠照片1张(贴于报名表指定位置); (5)如实填写的当年度二级建造师执业资格考试报名表(…

简单实现spring的set依赖注入

Maven依赖: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0…

http post协议发送本地压缩数据到服务器

1.客户端程序 import requests import os # 指定服务器的URL url "http://192.168.1.9:8000/upload"# 压缩包文件路径 folder_name "upload" file_name "test.7z" headers {Folder-Name: folder_name,File-Name: file_name } # 发送POST请求…