CompletableFuture的默认线程池ForkJoinPool源码分析

开始

@Test
public void test12() throws InterruptedException {  先做一个单元测试
    CompletableFuture.runAsync(()->{  //在此处打断点
        System.out.println("111");
    });
    Thread.sleep(400000);
}

一步一步把代码贴出来,看官看*好。

public static CompletableFuture runAsync(Runnable runnable) {  //运行线程的方法
    return asyncRunStage(asyncPool, runnable);
}

asyncPool是什么?看一下这个值的设置。

private static final Executor asyncPool = useCommonPool ?
    ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

useCommonPool是什么?

private static final boolean useCommonPool =
    (ForkJoinPool.getCommonPoolParallelism() > 1);
public static int getCommonPoolParallelism() {
    return commonParallelism;
}

commonParallelism就是那个并发的线程数,它又是怎么来的呢?

static {
    // initialize field offsets for CAS etc
    。。。。。。
    commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
    defaultForkJoinWorkerThreadFactory =
        new DefaultForkJoinWorkerThreadFactory();
    modifyThreadPermission = new RuntimePermission("modifyThread");
 
    common = java.security.AccessController.doPrivileged
        (new java.security.PrivilegedAction() {
            public ForkJoinPool run() { return makeCommonPool(); }});  //重点看makeCommonPool方法
    int par = common.config & SMASK; // 获取到par SMASK的值是 65535 也就是1111111111111111  &操作还是common.config本身,看样子还是要看看config是怎么来的
    commonParallelism = par > 0 ? par : 1;  想知道par是什么值,这个值为负数默认是1
}
private static ForkJoinPool makeCommonPool() {
    int parallelism = -1;  //这个并发的线程数默认是-1
    ForkJoinWorkerThreadFactory factory = null;
  。。。。。。
    if (parallelism < 0 && 
        (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)  //看到了吧,线程池中的处理线程数=电脑核数-1
        parallelism = 1;
    if (parallelism > MAX_CAP)
        parallelism = MAX_CAP;
    return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
                            "ForkJoinPool.commonPool-worker-");  //指定线程的名字
}

总结: 

1.ForkJoinPool将运行线程的最大数量限制为32767。尝试创建大于最大数目的池会导致{@code IllegalArgumentException}。

这个实现只在池关闭或者内部资源耗尽的时候才拒绝提交任务。通过抛出RejectedExecutionException异常。--就是说任务队列无限大, 拒绝策略就是一直可以接收任务.

2.CompletableFuture默认使用的线程池是 ForkJoinPool.commonPool(),commonPool是当前 JVM(进程) 上的所有 CompletableFuture、并行 Stream 共享的.

3.如果你cpu核数-1大于1,也就是你的cpu是小于等于两核,那么默认线程池会直接退化为 ThreadPerTaskExecutor,每个任务新开一个线程。

4.如果你的cpu核数大于2,那么池内的核心线程数就是cpu核数-1, 比如你的核心数是4核的,那么会使用默认的线程池ForkJoinPool,池内的核心线程数为3.

建议:

大家在用CompletableFuture时,要用自己定义的线程池来代替默认的线程池 ForkJoinPool.commonPool().因为ForkJoinPool.commonPool()仅适合cpu密集型任务,不适合io密集型任务.

如果服务是cpu密集型的,设置为电脑的核数

如果服务是io密集型的,设置为电脑的核数*2

你可能感兴趣的:(java,log4j,前端)