异步线程执行以及线程返回值的使用
使用CompletableFuture异步执行(有返回值)
1 supplyAsync方法
如果自己定义了线程的Executor的线程池的工具类,可以传入Executor类型的参数
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(ASYNC_POOL, supplier);
}
/**
* Returns a new CompletableFuture that is asynchronously completed
* by a task running in the given executor with the value obtained
* by calling the given Supplier.
*
* @param supplier a function returning the value to be used
* to complete the returned CompletableFuture
* @param executor the executor to use for asynchronous execution
* @param <U> the function's return type
* @return the new CompletableFuture
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
1.1 使用CompletableFuture异步执行任务并得到返回值
package 多线程测试;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
/**
* @author
* @desc 使用CompletableFuture创建线程使用返回值并执行
* CompletableFuture用于异步编程,异步通常意味着非阻塞,使我们的任务单独运行在与主线程分离的其他线程中 ,并且通过回调可以在主线程中得到异步任务的执行状态 是否完成和是否异常等 并行方式
* 不需要一直等到子线程完成 -- 优点:主线程可以并行的执行其他任务 提高性能
* @date
*/
public class ThreadTest {
// 使用CompletableFuture创建线程使用返回值并执行
public static void main(String[] args) {
ArrayList<String> partions = new ArrayList();
//supplyAsync(Supplier)
CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(new Supplier<>() {
@Override
public List<String> get() {
//对
return new ArrayList<>();
}
});
//supplyAsync(Supplier,Executor 自己写的线程工具类)
CompletableFuture<List<String>> future1 = CompletableFuture.supplyAsync(new Supplier<>() {
@Override
public List<String> get() {
//对list进行处理
return new ArrayList<>();
}
},ThreadUtils.achieveThread());
//收集线程返回值 CompletableFuture的get方法 主线程(程序跑的话 总会收集全 但是主线程不会阻塞)
try {
List<String> strings = future.get();
System.out.println(strings);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
/**
* @author
* @desc 线程池工具类 ThreadPoolExecutor
* @date
*/
@Slf4j
public class ThreadUtils {
/**
* 当前机器的CPU核数
*/
private static final Integer CORE_NUM = Runtime.getRuntime().availableProcessors();
/**
* 自定义线程池
*/
private static ExecutorService executorService = new ThreadPoolExecutor(3,CORE_NUM+1,0L, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(200));
/**
* 获取线程池
* @return
*/
public static ExecutorService achieveThread() {
// log.info("CORE_NUM={}",CORE_NUM);
return executorService;
}
}
1.1.1 List的循环过程中实现异步执行
package 多线程测试;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* @author
* @desc List 循环中过滤 开启线程
* @date
*/
public class ThreadMapCycle {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("yuepengcheng");
list.add("xingjie");
list.add("goujian");
list.add("yueyun");
list.add("积极上进");
List<List<String>> partition = Lists.partition(list,2); //
System.out.println(partition); // [[yuepengcheng,xingjie],[goujian,yueyun],[积极上进]]
List<CompletableFuture<List<String>>> futures = partition.stream().map(new Function<List<String>, CompletableFuture<List<String>>>() {
@Override
public CompletableFuture<List<String>> apply(List<String> strings) {
return CompletableFuture.supplyAsync(new Supplier<List<String>>() {
//get方法返回的是List<String> 泛型就是这个
@Override
public List<String> get() {
return null;
}
});
}
}).collect(Collectors.toList());
CompletableFuture<List<String>> future = futures.get(0); //第一个list [yuepengcheng,xingjie]做的变形
CompletableFuture<List<String>> future1 = futures.get(1); // 第二个list [goujian,yueyun]
}
}
2 new Thread来异步执行任务(无返回值)
package 多线程测试;
/**
* @author
* @desc new Thread重写run方法实现异步线程
* @date
*/
public class NewThread {
public void test() {
//其他处理逻辑
Thread thread = new Thread() {
@Override
public void run() {
//线程内执行的任务
}
};
//主线程其他处理逻辑
}
}
3 spring的异步注解@Async实现异步线程
创建异步线程类 使用@Async注解修饰方法
package com.sinog.front.asynctask;
import com.sinog.core.domain.InterfaceLog;
import com.sinog.core.domain.JieKouLog;
import com.sinog.front.feign.biz.api.LogInsertService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @desc 接口日志异步插入省级日志表和部级日志表
* @author ypc
* @date 2022/10/20
*/
@Slf4j
@Component
public class AsyncTaskLog {
@Autowired
private LogInsertService logInsertService;
/**
* 异步执行插入省级日志表数据
* @param interfaceLog 省级日志表实体类
*/
@Async("taskAsync01-")
public void asyncInsertSjLog(InterfaceLog interfaceLog){
log.info(Thread.currentThread().getName());
logInsertService.insertLog(interfaceLog);
}
/**
* 异步执行插入部级日志表数据
* @param jieKouLog sfb接口对接日志实体类
*/
@Async("taskAsync01-")
public void asyncInsertbjLog(JieKouLog jieKouLog){
log.info(Thread.currentThread().getName());
logInsertService.insertbuLog(jieKouLog);
}
}
不影响主线程结束 前端页面可以继续操作 异步线程来执行保存动作
@RequestMapping(value = "/transmission/api/azbj/savePreArrangedPersonnel", method = RequestMethod.POST, produces = "application/json;charset=utf-8;")
public Result savePreArrangedPersonnel(@RequestBody String data) {
//其他处理逻辑
try{
//其他处理逻辑
}catch(){
.....
}finally{
//最终要执行的逻辑
//异步执行2个方法(动作)
asyncTask.asyncInsertSjLog(interfaceLog);
asyncTask.asyncInsertbjLog(jieKouLog);
}
}
4 使用线程池的方法实现异步线程
4.1 Executors类实现异步编程
execute方法
public static void main(String[] args) {
// 使用Executors快速创建一个有2个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable runnable = new Runnable() {
@Override
public void run() {
//同步数据到省级 - 中间库 执行一个比较慢的同步数据的任务
System.out.println("子线程结束");
}
};
// 无返回值 execute
executor.execute(runnable);
System.out.println("保存成功,给前端响应");
}
submit方法
public static void main(String[] args) {
// 创建一个有2个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
//2种写法
// executor.submit(new Callable<String>() {
// @Override
// public String call() throws Exception {
// if (StringUtils.equals(dataSyncFashion, "middle")) {
// SYNC_INTERFACE.syncSjSqlBySql(finalSqlS, name, finalNativepro, finalPrino, finalTemplate);
// } else {
// log.error(">>>>>系统数据同步方式配置错误,可选值['http','middle']<<<<<");
// }
// return "ok";
// }
// });
Callable<String> callable = new Callable<>() {
@Override
public String call() throws Exception {
//处理逻辑
System.out.println("子线程");
return "返回的值";
}
};
//executor的submit方法里面传Callable 可获得返回值
Future<String> submit = executor.submit(callable);
//主线程逻辑
System.out.println("主线程继续走");
String s = "";
try {
// 子线程处理不完 主线程会暂停到这里
s = submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//
System.out.println("主线程结束得到"+s);
}
4.2 ThreadPoolTaskExecutor 自定义线程池
ThreadPoolTaskExecutor本身就是一个线程池 – 可自定义 – 可使用submit executor方法
public class Executor2 {
//ThreadPoolTaskExecutor 静态代码块来初始化一个线程池 也可以使用submit(有返回值) 和 execute方法
private static final ThreadPoolTaskExecutor EXECUTOR = new ThreadPoolTaskExecutor();
static {
EXECUTOR.initialize();
//核心线程数
EXECUTOR.setCorePoolSize(50);
//最大线程数
EXECUTOR.setMaxPoolSize(100);
//缓冲队列
EXECUTOR.setQueueCapacity(500);
//允许线程的空闲时间
EXECUTOR.setKeepAliveSeconds(1);
//线程前缀
EXECUTOR.setThreadNamePrefix("taskAsync001-");
//线程策略
EXECUTOR.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
EXECUTOR.setWaitForTasksToCompleteOnShutdown(true);
EXECUTOR.setAwaitTerminationSeconds(60);
}
//其他方法中可使用这个线程池
}