多线程执行List的addAll方法产生的并发问题

问题分析

将查询条件subList分为70个一组,通过CompletableFuture执行异步多线程分批次查询数据库,查询完成后在whenCompleteAsync方法中将结果存储在resultList中。

诡异的情况发生了,查询出来的结果resultList中有10000个数据,其中70 * n个为null的对象

try {
    //分页的参数 每个大小70 总大小100000
    List<List<Long>> subList = ......;
    //结果集
    List<QueryEntity> resultList = new ArrayList<>();
    //全流式处理转换成CompletableFuture[]+组装成一个无返回值CompletableFuture,join等待执行完毕。返回结果whenComplete获取
    CompletableFuture[] cfs = subList.stream().map(list -> CompletableFuture.supplyAsync(() -> querySQLList(list), threadPoolTaskExecutor).whenCompleteAsync((v, e) -> {
             resultList.addAll(v);
           })).toArray(CompletableFuture[]::new);
    //等待总任务完成,但是封装后无返回值,必须自己whenComplete()获取
    CompletableFuture.allOf(cfs).join();
    
    log.info("结果集中空对象的个数: " + resultList.stream().filter(Objects::isNull).count());
    //结果集中空对象的个数: 70
    
} catch (Exception e) {
    throw new RuntimeException("异常", e);
}

问题排查

猜测1:查询数据库的问题

查询数据库的过程中,因为网络或者其他原因导致查询出来的结果为null

List<QueryEntity> querySQLList(List<Long> paramList) {
    List<QueryEntity> resultList = this.sqlMapper.querySQL(paramList);
    log.info("结果集中空对象的个数: " + resultList.stream().filter(Objects::isNull).count());
    //结果集中空对象的个数: 0
    return resultList;
}

执行方法后,日志打印的空对象个数都是0,所以这一步能查到数据

猜测2: whenCompleteAsync方法的问题

怀疑是whenCompleteAsync方法接受的参数为List中全是空参数,于是在方法中增加日志

CompletableFuture[] cfs = subList.stream().map(list -> CompletableFuture.supplyAsync(() -> querySQLList(list), threadPoolTaskExecutor).whenCompleteAsync((v, e) -> {
             resultList.addAll(v);
    		log.info("结果集中空对象的个数: " + resultList.stream().filter(Objects::isNull).count());
    		//结果集中空对象的个数: 0
           })).toArray(CompletableFuture[]::new);
    //等待总任务完成,但是封装后无返回值,必须自己whenComplete()获取
    CompletableFuture.allOf(cfs).join();

但是结果也是空对象个数都是0

最终原因

因为是异步多线程,所有有可能会产生并发问题。因为数据大小为10000,一个数据不多也不少,所以一开始没想到是并发导致的问题。

CopyOnWriteArrayList是线程安全的List,替换ArrayList后,就没有发生过List中为空的问题了

//结果集
List<QueryEntity> resultList = new CopyOnWriteArrayList<>();
//....分片查询

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web安全---CSRF漏洞/OWASP-CSRFTester的使用

what 跨站请求伪造 Cross Site Request Forgery how 攻击者诱骗点击恶意网页&#xff0c;盗用&#xff08;伪造&#xff09;受害者的身份&#xff0c;以受害者的名义向服务器发送恶意请求,而这种恶意请求在服务端看起来是正常请求 CSRF&&XSS区别 他们最本质区别就…

什么是中间件?中间件有哪些?

什么是中间件&#xff1f; 中间件&#xff08;Middleware&#xff09;是指在客户端和服务器之间的一层软件组件&#xff0c;用于处理请求和响应的过程。 中间件是指介于两个不同系统之间的软件组件&#xff0c;它可以在两个系统之间传递、处理、转换数据&#xff0c;以达到协…

ArcGIS基础:便捷分享图层包和地图包

1、分享图层包&#xff1a; 首先&#xff0c;选中要分享的数据&#xff0c;右键创建图层包&#xff0c;修改保存路径。 找到项目描述那一栏&#xff0c;将摘要、标签、描述都填写分享图层包的相关内容。 一切设置好之后&#xff0c;点击右上角的【分析】按钮。 点击分析之后…

linux下安装anaconda

顺手点个关注吧&#xff0c;谢谢&#xff01; 一、下载安装包 https://repo.anaconda.com/archive/ 或者使用命令 wget https://repo.anaconda.com/archive/Anaconda3-5.3.1-Linux-x86_64.sh2.赋予权限并安装 # 给文件执行权限 chmod 777 Anaconda3-5.3.1-Linux-x86_64.sh# 执…

高频面试题:在浏览器搜索框中输入一个URL的完整请求过程?

相信很多小伙伴在校招或者社招面试中都遇到过这个问题 面试官&#xff1a;小伙子&#xff0c;了解 在浏览器搜索框中输入一个URL的完整请求过程吗&#xff1f;详细说说我&#xff1a;eeemm&#xff0c;不太清出具体的过程。整体过程应该是HTTP请求的过程。 如果在面试中不能很…

FinClip :可以让小程序脱离微信环境最快运行在自有App中

&#x1f9d0; 什么是FinClip&#xff1f; FinClip&#xff0c;一个可以让小程序脱离微信环境&#xff0c;最快运行在自有App中的神器。它支持在iPhone、Android、Windows、Linux、macOS、统信等平台下的应用中运行小程序&#xff0c;这意味着&#xff0c;无论是移动端、PC端&…

uniapp自定义返回事件(封装)

uniapp自定义返回事件 在我们使用uniapp时&#xff0c;我们导航栏一般都是自定义的&#xff0c;比如用uview框架的导航栏&#xff0c;那么返回事件通常会遇到以下几个问题 返回事件前需要做一些额外的处理 h5项目刷新页面后返回失效 返回按钮点击后到指定页面 如果只是监听返…

技术团队的管理方法和日常总结建议

管理学家德鲁克有言“管理是一种实践&#xff0c;其本质不在于知&#xff0c;而在于行&#xff0c;其验证不在于逻辑&#xff0c;而在于成果&#xff0c;其唯一的权威就是成就” &#xff0c;因此管理重实践看效果&#xff0c;但如果管理实践有理论依凭&#xff0c;那么实践起来…

新媒体运营-----短视频运营-----PR视频剪辑----视频调色

新媒体运营-----短视频运营-----PR视频剪辑-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/138079659 文章目录 1. Lumetri调色&#xff0c;明暗对比度2. Lumetri调色&#xff0c;创意与矢量示波器2.1 创意2.2 矢量示波器 3. L…

滑块验证码破解----Java使用opencv后端破解滑块验证

使用技术:Java SpringBootopenCV 在windows上首先需要下载opencv进行安装,先去官网:Releases - OpenCV 下载这个windows版本的安装包 下载后直接安装解压就行,然后需要,然后找到安装位置里的这个文件: 你下载的是什么版本的,这里的数字就是多少,比如我下载4.5.3版本那么这…

分治策略 --- 快排归并

目录 分治-快排 一、颜色分类 二、排序数组 三、数组中的第K个最大元素 四、库存管理 分治-归并 一、排序数组 二、交易逆序对的总数 三、计算右侧小于当前元素的个数 四、翻转对 分治是一种思想&#xff0c;也就是将大问题分解成小问题&#xff0c;一直分到小问题可…

2024年云仓酒庄新动态合肥北京双城开课,持续培训助力酒业发展

云仓酒庄合肥北京双城开课&#xff0c;持续培训助力酒业发展 随着国内酒类市场的不断繁荣与消费需求的日益增长&#xff0c;云仓酒庄作为行业内的稳扎稳打之一的企业&#xff0c;始终致力于提升服务质量和品牌影响力。近日&#xff0c;云仓酒庄在合肥与北京两地同时开设培训课…

qt学习篇---C++基础学习

本学习笔记学习下面视频总结&#xff0c;感兴趣可以去学习。讲的很详细 【北京迅为】嵌入式学习之QT学习篇_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1tp4y1i7EJ/?spm_id_from333.337.search-card.all.click&vd_source8827cc0da16223b9f2ad8ae7111de9e2 目录 C…

JavaScript数组方法练习

第一个练习 ● 计算所有账户的存款总额 const bankDepositSum accounts //定义一个变量.flatMap(acc > acc.movements) //使用flatmap将所有的存款提取&#xff0c;然后组成一个新的数组.filter(mov > mov > 0) //使用filter方法提取所有的正值.reduce((sum, c…

【前端】VUE项目创建

在所需文件夹中打开cmd命令行窗口&#xff0c;输入vue ui 进入web可视化界面选择创建新项目 根据需求依次完成下列选择&#xff0c;下列是参考配置&#xff0c;完成后点击创建项目即可 最终显示完成

upload-labs后续(14-)

图片马 在图片中加入木马&#xff0c;然后上传让浏览器解析&#xff0c;达到上传木马的目的 制作图片马&#xff1a;可以在notepad或者winhex中打开文件&#xff0c;在文件头中加入图片的文件头&#xff0c;再在文件末尾加入木马即可。 图片文件头如下&#xff1a; 1.Png图片…

B站广告推广开户最低需要多少钱?

在竞争激烈的互联网营销环境中&#xff0c;哔哩哔哩&#xff08;B站&#xff09;作为深受年轻人喜爱的视频分享平台&#xff0c;其广告价值不容小觑。对于希望在B站上进行广告推广的企业或个人而言&#xff0c;了解开户流程及成本&#xff0c;选择专业的服务团队至关重要。介绍…

AI图书推荐:ChatGPT写论文的流程与策略

论文一直是任何学术学位的顶峰。它展示了学生在研究领域的兴趣和专业知识。撰写论文也是一个学习经验&#xff0c;为学术工作以及专业研究角色做好准备。但是&#xff0c;论文工作总是艰苦的&#xff0c;通常是充满乐趣和创造性的&#xff0c;但有时也是乏味和无聊的。生成式人…

kerberos-hive-dbeaver问题总结

一、kerberos安装windows客户端 1、官方下载地址 http://web.mit.edu/kerberos/dist/ 2、环境变量配置 下载msi安装包&#xff0c;无需重启计算机&#xff0c;调整环境变量在jdk的前面&#xff0c;尽量靠前&#xff0c;因为jdk也带了kinit、klist等命令 C:\Program Files\…

Kotlin泛型之 循环引用泛型(A的泛型是B的子类,B的泛型是A的子类)

IDE(编辑器)报错 循环引用泛型是我起的名字&#xff0c;不知道官方的名字是什么。这个问题是我在定义Android 的MVP时提出来的。具体是什么样的呢&#xff1f;我们看一下我的基础的MVP定义&#xff1a; interface IPresenter<V> { fun getView(): V }interface IVie…
最新文章