Java CompletableFuture因在上下文中使用共享变量,导致线程安全问题

news/2024/11/18 6:21:51/文章来源:https://www.cnblogs.com/lingyejun/p/18293069

背景

在使用CompletableFuture.supplyAsync()时,多个异步中,同时共用的一个查询对象参数,而且在这多个任务中间会穿插地对这个对象进行更改,出现的现象就是可能会导致最终get()结果不符合我们的预期。最终调整方案就是在每个任务supplyAsync()之前单独赋予一个新的final对象只为此任务使用,不再进行共用。

CompletableFuture简介

CompletableFuture是Java8引入的一个类,用于在异步编程中处理多个任务。它可以将任务链接起来,使得一个任务的结果可以作为另一个任务的输入。CompletableFuture提供了丰富的方法来处理任务的结果,例如处理异常、合并多个任务的结果等。

CompletableFuture可以通过工厂方法创建,例如CompletableFuture.supplyAsync()用于执行一个有返回值的异步任务,CompletableFuture.runAsync()用于执行一个没有返回值的异步任务。

CompletableFuture的线程安全问题
虽然CompletableFuture提供了强大的功能,但在多线程环境中使用时,需要注意其线程安全问题。

1. 共享变量引发的问题

如果多个任务共享一个变量,并且对该变量进行修改操作,可能会导致不确定的结果。例如下面的代码:

public class CompletableFutureDemo {private static int count = 0;public static void main(String[] args) {CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {for (int i = 0; i < 1000; i++) {count++;}});CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {for (int i = 0; i < 1000; i++) {count++;}});CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2);combinedFuture.join();System.out.println("Count: " + count);}
}

在上面的代码中,两个任务分别对count变量进行1000次增加操作。由于count变量是共享的,这个操作并不是线程安全的。当两个任务交替执行时,可能会导致count的值不是预期的2000。

2. 竞态条件

CompletableFuture的方法可以通过多个线程同时调用,这可能导致竞态条件。例如,以下代码中的thenApply()方法会在前一个任务完成后执行,返回一个新的CompletableFuture对象。

public class CompletableFutureDemo {private static int count = 0;public static void main(String[] args) {CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {return 1;});CompletableFuture<Integer> future2 = future1.thenApply((result) -> {return result + 2;});CompletableFuture<Integer> future3 = future1.thenApply((result) -> {return result * 2;});CompletableFuture<Integer> combinedFuture = CompletableFuture.allOf(future2, future3);combinedFuture.join();System.out.println("Future2 result: " + future2.get());System.out.println("Future3 result: " + future3.get());}
}

在上面的代码中,future2和future3都依赖于future1的结果,但它们之间并没有明确的顺序关系。如果多个线程同时调用thenApply方法,可能会导致future2和future3的结果不一致,因为它们有可能使用了不同的future1结果。 

解决CompletableFuture的线程安全问题

为了解决CompletableFuture的线程安全问题,可以采取以下措施:

避免共享变量:在多个任务之间尽量避免共享变量,使用局部变量或者将变量作为方法参数传递。
使用线程安全的数据结构:如果必须共享变量,可以使用线程安全的数据结构,例如AtomicInteger代替int。
使用同步机制:可以使用synchronized关键字或者Lock接口来保证多个任务的互斥访问。

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

首发链接:https://www.cnblogs.com/lingyejun/p/18293069

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

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

相关文章

MySQL中修改一个数据库下包含有某个相同字段的所有表的字段长度

背景 由于业务场景导致某个字段如phone_name涉及到表比较多,目前很多表都有冗余这个字段,但是前期给的字段长度只有varchar(100),不满足目前的需要了,需要把所有的表的字段长度都增大到varchar(255),如果手动一个个修改的话,那么有几百张表,很花时间,所有想到如下办法,…

领取serv00免费虚拟主机

参考 ‍ 教程地址【免费serv00虚拟机SSH登录搭建网站】 ‍ 领取地址 ​​ 领到了 ​​ 登录成功 ​​ 放放上自己的静态网站 ​​ ‍ soulio.serv00.net 缺点:网站的URL中含有中文就会404。权限很少,改不了服务器配置。如果是nginx就好了,nginx支持中文路径。 ​​ URL全英文…

新版mac配置多版本JDK切换和maven套件

新版mac配置多版本JDK和maven套件 新版本的macOS Sonoma系统配置多版本的JDK和Maven开发套件。有平时开发和学习用到的JDK是不同版本的需求,就直接安装多个版本的JDK,使用的时候直接命令进行对应版本的切换,要做到切换JDK版本,可以自己配置并在终端切换,或者使用java的版本…

4.show

学习 Admonitions(警告) - Material for MkDocs (wdk-docs.github.io) 提示 - Material for MkDocs 中文文档 (llango.com) Buttons(按钮) - Material for MkDocs (wdk-docs.github.io) 建议去看这些网站,更为详细。常用功能 便利贴 ​​ 开启 markdown_extensions:- admoniti…

5.更多

发现一个项目与 MkDocs 类似的项目 PyMdown 拓展文档 ,等待探索。1.排版模仿 以下网站使用 MkDocs 构建Material for MkDocs 的美化 - Charles Les Notebook (charleschile.com)Documentation - Home Assistant (home-assistant.io)Godot Docs – master branch — Godot Engi…

6.附录

安装插件 在 MkDocs 中,插件通常是通过 pip​ 工具安装的。你可以使用以下步骤来安装和配置 MkDocs 插件。 1.使用 pip​ 命令安装你需要的插件。例如 pip install pymdown-extensions‍ 2.更新 mkdocs.yml​ 文件。 ‍ 3.使用 mkdocs serve​ 命令本地预览你的文档网站。 ‍ …

2.快速上手MkDocs

快速上手 !!! info "注意" 每次使用 MkDocs 首先进入 python 虚拟环境。 创建项目 mkdocs new ~/mkdocs/预览网站 cd ~/mkdocs/ mkdocs serve 127.0.0.1:8000​ 预览效果 ​​ 构建网站 mkdocs build项目结构 项目结构 ├── docs/ │ └── index.md ├── …

谷歌语法

谷歌语法:帮助我们更好的检索有用信息 1、site:指定域名 例如:在博客园当中查找学习文章 site:cnblogs.com2、intitle:搜索网页标题中的关键字 例如:在博客园当中查找网页标题中包含mysql的学习文章 site:cnblogs.com intitle:MYSQL常用SQL语句3、intext:搜索网页正文中的…

证书-双证书请求文件

1.背景关于数字证书、数字信封、OID等基本知识,此文不做赘述。在传统的数字信封体系中,我们的流程大概这样的。这里有个值得注意的点是: 节点1用于加密对称密钥的公钥和节点3用于签名的私钥,它们是否可以是同一对。 基于这个思想,我们有了单证书体系和双证书体系。 其原因…

[数据结构] 二叉搜索树基本操作

这篇文章记录了二叉搜索树的基本操作定义 二叉搜索树是一种特殊的二叉树,其定义如下:空树是二叉搜索树。 若二叉搜索树的左子树不为空,则其左子树上所有点的附加权值均小于其根节点的值。 若二叉搜索树的右子树不为空,则其右子树上所有点的附加权值均大于其根节点的值。 二…

014 批处理系统

写在前面 本随笔是非常菜的菜鸡写的。如有问题请及时提出。 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 本章目的保障系统安全 多应用支持本章需要实现的新功能构造包含操作系统内核和多个应用程序的单一执行程序 通过批处理支持多个程…

DOM属性

常用 DOM 属性innerHTML:用于获取或设置元素的 HTML 内容。 可以直接插入 HTML 代码,适合处理复杂的 HTML 结构。element.innerHTML = <p>New content</p>; console.log(element.innerHTML);innerText:用于获取或设置元素的文本内容,只包括可见的文本。 会触发重…