CompletableFuture.runAsync的多线程下异步操作

news2024/11/27 7:41:03

在这里插入图片描述

CompletableFuture.runAsync的多线程下异步操作

🧰业务使用场景

CompletableFuture.runAsync()​方法是Java中用于创建异步任务的工具,它可以在后台线程中执行指定的任务,并且可以在任务完成后返回结果或执行后续操作。这种方式可以实现多线程下的异步操作。

在多线程环境下,使用CompletableFuture.runAsync()​可以实现并发执行多个任务,提高程序的性能和效率。每个异步任务都会在独立的线程中执行,互不影响,从而可以充分利用多核处理器的性能。

❗需要注意的点

在使用CompletableFuture.runAsync()​方法创建异步任务时,需要注意以下几个问题:

  1. 共享变量的线程安全性:如果异步任务需要访问或修改共享的变量,需要确保对这些变量的访问是线程安全的。可以使用Atomic​类、synchronized​关键字、Lock​等方式来保证共享变量的线程安全性。
  2. 变量的可见性:在多线程环境下,不同线程对同一个变量的修改可能不会立即对其他线程可见。可以使用volatile​关键字来保证变量的可见性,或者通过CompletableFuture​的一些方法来确保任务之间的数据传递和可见性。
  3. 避免数据竞争:在多线程环境下,可能会出现数据竞争的情况,即多个线程对同一变量进行读写操作,导致数据不一致。需要谨慎设计并发操作,避免数据竞争问题的发生。
  4. 异常处理:异步任务可能会抛出异常,需要在适当的地方捕获和处理异常,以避免程序崩溃或出现未知错误。
  5. 线程池的使用CompletableFuture.runAsync()​默认使用ForkJoinPool.commonPool()​来执行任务,如果需要更精细地控制线程池的大小或其他属性,可以使用CompletableFuture.supplyAsync()​方法并传入自定义的Executor​来创建异步任务 。
📝代码示例
package com.fjh.demo.thread;

import com.fjh.demo.dto.scope.ResultView;
import com.fjh.demo.util.DynamicDataUtil;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @ClassName: CompletableFutureDemo
 * @Description: TODO 多线程下异步操作
 * @Author: fengjiahao
 * @Date: 2024/6/15 16:01
 */
public class CompletableFutureDemo {
    public static ResultView resultView;
    public static void main(String[] args)throws Exception {
        CompletableFutureDemo demo = new CompletableFutureDemo();
        //随机生成数据,该工具类可以自己实现ResultView 和DynamicDataUtil都是自己实现
        resultView = DynamicDataUtil.generateRandomObject(ResultView.class);
        //开启两个线程同时处理
       Thread thread1 =  new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"开始处理");
                demo.syncHandle();
            }
        });
        Thread thread2 =  new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"开始处理");
                demo.syncHandle();
            }
        });
       thread1.setName("线程1");
       thread2.setName("线程2");

        thread1.start();
        thread2.start();

    }

    public void syncHandle()  {
        System.out.println(resultView.toString());
        //线程可见性,共享(如果需要线程私有那么就需要使用到ThreadLocal,视场景采用)
        AtomicReference<ResultView> viewAtomic = new AtomicReference<>(resultView);
        CompletableFuture.runAsync(() -> {
            ResultView view= viewAtomic.get();
            view.setName(Thread.currentThread().getName());
            System.out.println("异步修改后:"+view.toString());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("修改后:"+resultView.toString());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("修改后:"+resultView.toString());
    }



}

  • 🪲结果

    
    线程2开始处理
    线程1开始处理
    ResultView{id=87, name='孙赵', amount=0.7525627958447209}
    ResultView{id=87, name='孙赵', amount=0.7525627958447209}
    修改后:ResultView{id=87, name='孙赵', amount=0.7525627958447209}
    修改后:ResultView{id=87, name='孙赵', amount=0.7525627958447209}
    异步修改后:ResultView{id=87, name='ForkJoinPool.commonPool-worker-9', amount=0.7525627958447209}
    异步修改后:ResultView{id=87, name='ForkJoinPool.commonPool-worker-2', amount=0.7525627958447209}
    修改后:ResultView{id=87, name='ForkJoinPool.commonPool-worker-2', amount=0.7525627958447209}
    修改后:ResultView{id=87, name='ForkJoinPool.commonPool-worker-2', amount=0.7525627958447209}
    
    

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

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

相关文章

Elixir学习笔记——别名、需要、导入和使用

为了便于软件重用&#xff0c;Elixir 提供了三个指令&#xff08;alias、require 和 import&#xff09;以及一个名为 use 的宏&#xff0c;总结如下&#xff1a; # 为模块添加别名&#xff0c;以便可以将其称为 Bar 而不是 Foo.Bar alias Foo.Bar, as: Bar # 需要模块才能使…

数字化校园:打造未来教育新风尚

在21世纪的教育蓝图中&#xff0c;"数字化校园"正逐渐从愿景走向现实&#xff0c;它不仅是科技进步与教育创新深度融合的产物&#xff0c;更是重塑教育生态、引领未来学习风尚的关键力量。随着云计算、大数据、人工智能等前沿技术的蓬勃发展&#xff0c;传统的教育模…

基于RandLA-Net深度学习模型的激光点云语义分割

一、场景要素语义分割部分的文献阅读笔记 RandLA-Net是一种高效、轻量级的神经网络&#xff0c;其可直接逐点推理大规模点云的语义标签。RandLA-Net基于随机点采样获得了显著的计算和内存效率&#xff0c;并采用新的局部特征聚合模块有效地保留了几何细节&#xff0c;弥补了随机…

warning LNK4017: DESCRIPTION 语句不支持目标平台;已忽略

文章目录 warning LNK4017: DESCRIPTION 语句不支持目标平台&#xff1b;已忽略概述笔记备注END warning LNK4017: DESCRIPTION 语句不支持目标平台&#xff1b;已忽略 概述 基于ATL的COM DLL导出函数&#xff0c;无法用__declspec(dllexport)直接在函数上标记为导出函数。 只…

Linux crontabs定时执行任务

文章目录 前言一、安装二、服务1. 启动crond服务2. 关闭crond服务3. 重启crond服务4. 设置crond开机启动5. 禁用crond开机启动6. 查看crond是否开机启动7. 重新载入配置8. 查看crond运行状态 三、使用1. 查看当前用户的crontab2. 编辑用户的crontab3. 删除用户的crontab的内容 …

Linux基础命令[29]-chown

文章目录 1. chown 命令说明2. chown 命令语法3. chown 命令示例3.1 修改属主3.2 修改属组3.3 修改属主和属组3.4 修改文件夹所属 4. 总结 1. chown 命令说明 chown&#xff1a;更改文件的用户或用户组&#xff0c;需要 root 用户或 sudo 权限的用户执行该命令。基本信息如下&…

Elixir学习笔记——模块属性

Elixir 中的模块属性有三个用途&#xff1a; 1.作为模块和函数注释 2.作为编译期间使用的临时模块存储 3.作为编译时常量 让我们检查一下这些示例。 作为注释 Elixir 引入了 Erlang 中的模块属性概念。例如&#xff1a; 在上面的例子中&#xff0c;我们使用模块属性语法定义…

使用GNU Gcov Lcov生成C++单元测试代码覆盖率报告

最近在统计C项目代码的单元测试覆盖率 发现通过gcov和lcov就能将代码单元测试覆盖率定量化和可视化 下面是基于gtest测试框架&#xff0c;对gcov和lcov生成覆盖率的简单示例 工作流程 主要有三个步骤 向GCC编译添加特殊的编译选项以生成可执行文件和*.gcno 运行&#xff08…

Vue3 生命周期函数及其与Vue2的对比总结

Vue3 继续保留了 Vue2 的生命周期钩子&#xff0c;但在 Composition API&#xff08;setup 函数&#xff09;中&#xff0c;它们被改为了一组导入函数。以下是它们的对比&#xff1a; Vue2 生命周期钩子和 Vue3 对应的生命周期函数&#xff1a; 在 Vue3 中&#xff0c;所有的…

TJA1145休眠唤醒调试

目录 项目场景:TJA1145引脚图问题描述SPI链路验证休眠唤醒休眠唤醒配置唤醒报文配置代码相关寄存器:模式寄存器使能CAN唤醒设置唤醒边沿检测事件状态及捕获寄存器CANFD报文不会被识别为有效的唤醒帧项目场景: 最近开发过程中,选择了这颗芯片,踩了很多坑,总算是把这个芯片…

【C语言】解决C语言报错:Undefined Reference

文章目录 简介什么是Undefined ReferenceUndefined Reference的常见原因如何检测和调试Undefined Reference解决Undefined Reference的最佳实践详细实例解析示例1&#xff1a;缺少函数定义示例2&#xff1a;函数声明和定义不匹配示例3&#xff1a;未链接必要的库示例4&#xff…

UWB技术定位系统源码,智慧工厂人员定位系统,独特的射频处理,配合先进的位置算法

UWB技术定位系统源码&#xff0c;高精度人员定位系统源码&#xff0c;智慧工厂人员定位系统源码&#xff0c;室内定位系统源码 本套系统运用UWB定位技术&#xff0c;开发的高精度人员定位系统&#xff0c;通过独特的射频处理&#xff0c;配合先进的位置算法&#xff0c;可以有…

人工智能在风险管理中的创新之路

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面&#xff0c;尤其在风险管理领域&#xff0c;其展现出的巨大潜力令人瞩目。风险管理&#xff0c;作为一个涉及广泛领域的复杂系统&#xff0c;正逐渐依赖于AI技术来提升效率和准…

Linux文件系统【真的很详细】

目录 一.认识磁盘 1.1磁盘的物理结构 1.2磁盘的存储结构 1.3磁盘的逻辑存储结构 二.理解文件系统 2.1如何管理磁盘 2.2如何在磁盘中找到文件 2.3关于文件名 哈喽&#xff0c;大家好。今天我们学习文件系统&#xff0c;我们之前在Linux基础IO中研究的是进程和被打开文件…

将Jar用三种方式生成Windows的安装程序

无论是WEB(spring boot)的JAR,还是JavaFX以及swing的Jar,要生成windows方式。 打包成Windows可执行文件&#xff08;.exe&#xff09;&#xff0c;你可以使用以下三种方法&#xff1a; ### 方法1&#xff1a;使用Inno Setup 1. **构建JavaFX应用程序**&#xff1a; 使用M…

自制一个Linux live固件镜像ISO可引导系统

使用母盘镜像制作两个虚拟&#xff0c;来制作一个包含基本需求的filesystem.squashfs文件&#xff0c;具体看下面的链接 使用的安装镜像 是Linux Mint 制作好的成品 https://cloud.189.cn/t/U32Mvi7FnyA3 &#xff08;访问码&#xff1a;2nbo&#xff09; 最简单制作LIVE CD…

ChatGPT魔法背后的原理:如何做到词语接龙式输出?

介绍 我们都知道 ChatGPT 是 AIGC 工具&#xff0c;其实就是生成式人工智能。大家有没有想过这些问题 &#x1f914;️&#xff1a; 1、我们输入一段话&#xff0c;就可以看见它*噼里啪啦的一顿输出*&#xff0c;那么它的原理到底是什么&#xff1f; 2、到底它是怎么锁定这些…

【Prometheus】Prometheus的k8s部署

Kubernetes 集群部署 Prometheus 和 Grafana //实验环境 控制节点/master01 192.168.67.30 工作节点/node01 192.168.67.12 工作节点/node02 192.168.67.13 //node-exporter 安装 #创建监控 namespace kubectl create ns monitor-sa #部署 nod…

Java—装饰器模式

介绍 装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你动态地将行为添加到现有的对象中&#xff0c;而无需修改其代码。装饰器模式提供了比继承更灵活的功能扩展方式。 主要角色 Component&#xff1a;定义一个对…

【数据的增值之路】全生命周期的数据演化过程

引言&#xff1a;随着云计算、大数据、人工智能、区块链等新一代信息技术的快速发展&#xff0c;数据已经成为推动经济增长的重要生产要素。数据量的爆炸式增长&#xff0c;为挖掘数据价值、推动数字经济发展提供了丰富的资源基础。重要概念解析&#xff1a; 数据经济&#xf…