美文网首页
CompletableFuture避坑1——需要自定义线程池

CompletableFuture避坑1——需要自定义线程池

作者: 猫尾草 | 来源:发表于2021-07-25 21:57 被阅读0次

CompletableFuture避坑1——需要自定义线程池
CompletableFuture避坑2——allOf()超时时间不合理的后果
CompletableFuture避坑3——线程池的DiscardPolicy()导致整个程序卡死


1. 限制IO密集型任务的性能

CompletableFuture默认使用的线程池是 ForkJoinPool.commonPool(),commonPool是当前 JVM(进程) 上的所有 CompletableFuture、并行 Stream 共享的,commonPool 的目标场景是非阻塞的 CPU 密集型任务,其线程数默认为 CPU 数量减1,所以对于我们用java常做的IO密集型任务,默认线程池是远远不够使用的;在双核及以下机器上,默认线程池又会退化为为每个任务创建一个线程,相当于没有线程池。
以runAsync的代码举例,不指定线程池时,使用的是ASYNC_POOL,而这个ASYNC_POOL的大小,是根据 CPU 核数计算出来的(COMMON_PARALLELISM)如果COMMON_PARALLELISM小于1,USE_COMMON_POOL为false(此时ForkJoinPool.commonPool()不支持并发),直接退化为 ThreadPerTaskExecutor,每个任务新开一个线程。
下面是部分代码及注释。

          // 这段用来计算ForkJoinPool.commonPool()的线程池大小的
          static {
        try {
            MethodHandles.Lookup l = MethodHandles.lookup();
            CTL = l.findVarHandle(ForkJoinPool.class, "ctl", long.class);
            MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
            QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
        } catch (ReflectiveOperationException e) {
            throw new ExceptionInInitializerError(e);
        }

        Class<?> ensureLoaded = LockSupport.class;

        int commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
        try {
            String p = System.getProperty
                    ("java.util.concurrent.ForkJoinPool.common.maximumSpares");
            if (p != null)
                commonMaxSpares = Integer.parseInt(p);
        } catch (Exception ignore) {
        }
        COMMON_MAX_SPARES = commonMaxSpares;

        defaultForkJoinWorkerThreadFactory =
                new DefaultForkJoinWorkerThreadFactory();
        modifyThreadPermission = new RuntimePermission("modifyThread");

        common = AccessController.doPrivileged(new PrivilegedAction<>() {
            public ForkJoinPool run() {
                return new ForkJoinPool((byte) 0);
            }
        });

        COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
    }

    public static int getCommonPoolParallelism() {
        return commonParallelism;
    }

    // ForkJoinPool.commonPool()线程池大小为1或0,就不使用ForkJoinPool.commonPool()了
    private static final boolean USE_COMMON_POOL =
            (ForkJoinPool.getCommonPoolParallelism() > 1);

    // 为每个任务开一个线程的线程工厂
    static final class ThreadPerTaskExecutor implements Executor {
        public void execute(Runnable r) {
            new Thread(r).start();
        }
    }

    private static final Executor ASYNC_POOL = USE_COMMON_POOL ?
            ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

    public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(ASYNC_POOL, runnable);
    }

2. 子线程中不继承当前的类加载器

参考这个:https://zhuanlan.zhihu.com/p/339203275,作者已经写得很清楚了,我就不重复了。

相关文章

  • CompletableFuture使用方法

    一、自定义线程池 二、CompletableFuture使用

  • spring boot中设置异步请求默认使用的线程池

    1、自定义异步线程池,如果不自定义则使用自带的线程池(不是真正意义上的线程池,不会复用线程) 2、springbo...

  • 自定义线程池

    一、前言 前一节介绍了线程池基本参数和概念,下面说下如何自定义线程池。 二、自定义线程池 1、步骤 (1)编写任务...

  • 并发--共享模型之工具

    线程池 1.1 自定义线程池 先自定义任务队列 自定义线程池 测试: 定义拒绝策略接口: 1.2 ThreadPo...

  • java线程池源码分析

    从线程池使用进行实现分析一.自定义线程池1.自定义线程池2.构造完成之后状态3.关键参数介绍二.执行任务1.exe...

  • 2019-03-13 自定义连接池

    连接池:即线程池要自定义先要了解线程池模型,即线程池的核心参数1.coresize核心线程池,即运行的线程2.ma...

  • Java线程池

    一、自定义线程池集成ThreadPoolExecutor 二、JDK自带的几种线程池 1、newFixedThre...

  • kotlin协程

    作用:轻量级的线程,比线程更易用,便本质仍然是线程。 可以自定义线程池,自定义异常处理逻辑。需要自定义Contin...

  • 学习 CompletableFuture 进阶之前先掌握两种线程

    本来是准备直接写 CompletableFuture 线程池进阶文章的,但是总感觉不说一下线程池又不太好直接开展,...

  • 线程池模板

    线程池自定义工厂 线程池管理 使用

网友评论

      本文标题:CompletableFuture避坑1——需要自定义线程池

      本文链接:https://www.haomeiwen.com/subject/zctnmltx.html