文章目录
java多线程操作
(使用)CompletableFuture
线程池配置 ExecutorConfig
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
@Bean("myTaskExecutor")
public Executor myTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);//核心线程数量,线程池创建时候初始化的线程数
executor.setMaxPoolSize(15);//最大线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setQueueCapacity(200);//缓冲队列,用来缓冲执行任务的队列
executor.setKeepAliveSeconds(60);//当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setThreadNamePrefix("myTask-");//设置好了之后可以方便我们定位处理任务所在的线程池
executor.setWaitForTasksToCompleteOnShutdown(true);//用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
executor.setAwaitTerminationSeconds(60);//该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
//线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
使用 @Autowired @Qualifier注解自动注入
@Autowired
@Qualifier("myTaskExecutor")
private Executor executor;
1、runAsync和supplyAsync
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
-
runAsync没有返回值
-
supplyAsunc有返回值
-
Executor executor代表线程池,如果没有配置线程池将使用默认线程池(ForkJoinPool.commonPool())
示例
CompletableFuture<List<Map<String,Object>>> f1 =
CompletableFuture.supplyAsync(() -> this.mapper.accessNumByDay(Map), executor);
2、在线程完成时的回调函数
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
- 可以看到Action的类型是BiConsumer<? super T,? super Throwable>它可以处理正常的计算结果,或者异常情况。
- super T为当前CompletableFuture的结果类型
- whenComplete 和 whenCompleteAsync 的区别:
- whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
- whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
示例
f1.whenComplete((list, throwable) -> System.out.println("任务一:" + System.currentTimeMillis()));
3、将线程串行化(thenApple)
当一个线程的输入依赖另一个线程的输出时,将线程串行化
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
- super T 上一个线程的返回值
- extends U 当先线程的返回值
示例
private static void thenApply() throws Exception {
CompletableFuture<Long> future = CompletableFuture.supplyAsync(new Supplier<Long>() {
@Override
public Long get() {
long result = new Random().nextInt(100);
System.out.println("result1="+result);
return result;
}
}).thenApply(new Function<Long, Long>() {
@Override
public Long apply(Long t) {
long result = t*5;
System.out.println("result2="+result);
return result;
}
});
long result = future.get();
System.out.println(result);
}
4、thenCombine 合并任务
将两个任务的结果合并
public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
- 一个任务.thenCombine(另一个任务,(两个任务类型))
示例
CompletableFuture<List<Map<String,Object>>> f1 =
CompletableFuture.supplyAsync(() -> this.mapper.accessNumByDay(Map), executor);
CompletableFuture<List<Map<String,Object>>> f2 =
CompletableFuture.supplyAsync(() -> this.mapper.accessGroup(Map), executor);
CompletableFuture<Map<String,Object>> f3 = f1.thenCombine(f2, (list, list2) -> {
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("accessByDay",list);
resultMap.put("accessGroup",list2);
return resultMap;
}
);
return f3.join();
5、allOf 多种结合的调用
示例
@GetMapping("/getUserInfo5")
public String getUserInfo5() throws ExecutionException, InterruptedException {
CompletableFuture<String> future1
= CompletableFuture.supplyAsync(() -> "biandan");
CompletableFuture<String> future2
= CompletableFuture.supplyAsync(() -> "说");
CompletableFuture<String> future3
= CompletableFuture.supplyAsync(() -> "让天下没有难写的代码");
//返回的是 void 类型
CompletableFuture<Void> combinedFuture_1
= CompletableFuture.allOf(future1, future2, future3);
//使用 join 方法手动获取结果
String combinedFuture_2 = Stream.of(future1, future2, future3)
.map(CompletableFuture::join)
.collect(Collectors.joining(" "));
return combinedFuture_2;
}
- 注意 CompletableFuture.allOf 的返回类型是CompletableFuture。这种方法的局限性在于它不能返回所有 Supplier 的组合结果。我们必须从未来手动获取结果。使用 CompletableFuture.join() 方法获取。