CompletableFuture.runAsync的多线程下异步操作
🧰业务使用场景
CompletableFuture.runAsync()
方法是Java中用于创建异步任务的工具,它可以在后台线程中执行指定的任务,并且可以在任务完成后返回结果或执行后续操作。这种方式可以实现多线程下的异步操作。
在多线程环境下,使用CompletableFuture.runAsync()
可以实现并发执行多个任务,提高程序的性能和效率。每个异步任务都会在独立的线程中执行,互不影响,从而可以充分利用多核处理器的性能。
❗需要注意的点
在使用CompletableFuture.runAsync()
方法创建异步任务时,需要注意以下几个问题:
- 共享变量的线程安全性:如果异步任务需要访问或修改共享的变量,需要确保对这些变量的访问是线程安全的。可以使用
Atomic
类、synchronized
关键字、Lock
等方式来保证共享变量的线程安全性。 - 变量的可见性:在多线程环境下,不同线程对同一个变量的修改可能不会立即对其他线程可见。可以使用
volatile
关键字来保证变量的可见性,或者通过CompletableFuture
的一些方法来确保任务之间的数据传递和可见性。 - 避免数据竞争:在多线程环境下,可能会出现数据竞争的情况,即多个线程对同一变量进行读写操作,导致数据不一致。需要谨慎设计并发操作,避免数据竞争问题的发生。
- 异常处理:异步任务可能会抛出异常,需要在适当的地方捕获和处理异常,以避免程序崩溃或出现未知错误。
- 线程池的使用:
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}