parallelStream和completableFuture的线程池区别,以及Executors线程池的使用

parallelStream不能使用自定义线程池

list.stream().parallel().forEach(a -> {
            // 操作代码.....
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

并行流特点:
基于服务器内核的限制,如果你是八核,每次线程只能起八个,不能自定义线程池;
适用于对list密集计算操作充分利用CPU资源,如果需要调用远端服务不建议使用;

CompletableFuture支持使用自定义线程池

未使用自定义线程池

// supplyAsync需要有返回值,runAsync不需要有返回值
list.stream().map(a -> CompletableFuture.supplyAsync(() -> {
             // 操作代码.....
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return a;
        })).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());

未自定义线程池时默认线程池跟并行流一样,都是根据服务器内核数创建线程数量。

使用自定义线程池

ExecutorService executor = Executors.newFixedThreadPool(Math.min(list.size(), 100));

list.stream().map(a -> CompletableFuture.supplyAsync(() -> {
            // 操作代码.....
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return a;
        }, executor)).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());

补充:

  1. 线程数量的计算公式:
    T(线程数) = N(服务器内核数) * u(期望cpu利用率) * (1 + E(等待时间)/C(计算时间));
  2. 获取服务器内核数:
    int count = Runtime.getRuntime().availableProcessors();
  3. 划重点:
    此处join方法和CompletableFuture的get()方法类似,都是阻塞线程,等待结果,但是join方法不抛异常,不需要处理异常,让你代码更方便,get方法抛异常。

Executors使用(有多种线程池)

list.forEach(a ->
            executor.submit(() -> {
                // 操作代码.....
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            })
        );
        executor.shutdown();
        while (true) {
            if (executor.isTerminated()) {
                System.out.println("线程执行完毕!!!");
                break;
            }
            Thread.sleep(10);
        }

简单总结

可以将代码粘贴到idea中运行把运行时间打出来看看效果,最后发现:

parallel与未定义自线程池的CompletableFuture效果差别不大,原因是底层都使用的默认的线程池;
CompletableFuture自定义线程池与Executors的运行效果差别不大,但、
CompletableFuture有很多组合式的异步编程方法:
runAsync:异步执行没有返回值;
supplyAsync:异步执行有返回值;
thenApply:继续执行当前线程future完成的函数,不需要阻塞等待其处理完成;
thenApplyAsync:在不同线程池异步地应用参数中的函数;
thenCompose:用于多个彼此依赖的futrue进行串联起来
thenCombine:并联起两个独立的future,注意,这些future都是在长时间计算都完成以后


摘自:https://blog.51cto.com/u_12905373/6121385

posted on 2024-01-29 04:11  wucanqin  阅读(299)  评论(0编辑  收藏  举报

导航