文章目录

  • java多线程操作
  • (使用)CompletableFuture
  • 1、runAsync和supplyAsync
  • 示例
  • 2、在线程完成时的回调函数
  • 示例
  • 3、将线程串行化(thenApple)
  • 示例
  • 4、thenCombine 合并任务
  • 示例
  • 5、allOf 多种结合的调用
  • 示例


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 这个任务继续提交给线程池来进行执行。

示例

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() 方法获取。