首页 > 其他分享 >Excutors 与 ThreadPoolExcutor 的关系与区别

Excutors 与 ThreadPoolExcutor 的关系与区别

时间:2024-03-22 13:11:47浏览次数:24  
标签:ThreadPoolExcutor 区别 创建 Executors 线程 new Excutors public ThreadPoolExecutor

先说结论。
线程池的创建分为两种:

  • Executors
  • ThreadPoolExecutor

Executors 是一个线程池的工具类,而 ThreadPoolExecutorExecutors 的具体实现。ThreadPoolExecutorExecutor 接口的一个实现,是线程池的核心类。Executors 工具类提供了很多方法来创建不同类型的线程池,比如 newFixedThreadPool(创建固定线程数的线程池)、newCachedThreadPool(创建缓冲线程池)、newSingleThreadPool(创建只有一个线程的线程池)等,但内部都是通过构造 ThreadPoolExecutor 的不同参数实例来构造线程池的。
所以 Executors 适用于想快速创建一个线程池而不在意内部实现的场景,而 ThreadPoolExecutor 更为灵活可控,可自定义创建拥有特定配置的线程池。
说完的结论再来详细说说 ExecutorsThreadPoolExecutor

Executors

Executors 创建线程池的方式有以下几种:

  • Executors.newFixedThreadPool:创建固定大小的线程池
  • Executors.newWorkStealingPool:创建抢占式线程池
  • Executors.newSingleThreadExecutor:创建单个线程的线程池
  • Executors.newCachedThreadPool:创建可缓存的线程池
  • Executors.newSingleThreadScheduledExecutor:创建单线程可执行延迟任务的线程池
  • Executros.newScheduledThreadPool:创建可执行延迟任务的线程池

可以看下源码:

public class Executors {
    /**
     * 创建可重用的固定数量的线程池。如果所有线程都处在活动状态,提交额外任务
     * 的时候,超出的线程在队列中等待。队列类型是 LinkedBlockingQueue
     * nThreads 为创建线程池的数量
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    /**
     * Java 8 新增的线程池,具有抢占式操作的线程池,每个线程都有一个任务队列存放任务,
     * 当线程发现自己的队列没有任务了,也就是先工作完了的线程就去帮助没处理完的线程工作。
     * 以实现最快完成工作。
     * 是基于 ForkJoinPool 创建的线程池,parallelism 参数自定义并行度。
     */
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

    /**
     * 同上,但是并行度是根据获取当前系统的 CPU 核心数来判断。
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

    /**
     * 创建固定数量线程的线程池,可控制线程最大并发数,超出的线程会在队列中等待。
     * 多了一个 ThreadFactory 参数,线程工厂,主要用来创建线程池
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

    /**
     * 创建单个线程的线程池。它可以保证先进先出的执行顺序。
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    /**
     * 同上。
     */
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

    /**
     * 创建一个可缓存的线程池。适用于短期执行的异步任务,从代码中可以看出线程数的设定是
     * Integer.MAX_VALUE,不对线程池的大小做设定,可以创建无限数量的线程。
     * 但也就不适合执行长时间运行的任务,可能会导致系统资源耗尽。
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

    /**
     * 同上
     */
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

    /**
     * 创建一个单线程的可以执行延迟任务的线程池,可以安排以给定延迟后执行的命令或定时执行的命令。
     * 
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

    /**
     * 同上
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

    /**
     * 创建一个可以执行延迟任务的线程池,任务数量自定义
     */
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

    /**
     * 同上
     */
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
}

可以看到其实 Executors 创建的线程大部分都是由 ThreadPoolExecutor 实现。

ThreadPoolExecutor

直接看下他的构造函数:

public ThreadPoolExecutor(int corePoolSize, // 核心线程数,线程池中始终存活的线程数
                           // 最大线程数,线程池中允许的最大线程数
                          int maximumPoolSize,
                          // 最大线程数可以存活的时间
                          long keepAliveTime, 
                          // 时间单位
                          TimeUnit unit, 
                          // 阻塞队列,workQueue 包含七种
                          BlockingQueue<Runnable> workQueue, 
                           // 线程工厂,主要用来创建线程
                          ThreadFactory threadFactory,
                          // 拒绝策略
                          RejectedExecutionHandler handler ) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    this.prestartAllCoreThreads();
}

ThreadPoolExecutor 的执行原理如图:

标签:ThreadPoolExcutor,区别,创建,Executors,线程,new,Excutors,public,ThreadPoolExecutor
From: https://www.cnblogs.com/knqiufan/p/18089234

相关文章

  • 自动驾驶和人形机器人的技术区别点在哪里?
    特斯拉的马斯克说过,人形机器人就是没有汽车轮子的自动驾驶,这句话虽然听着有些搞笑,但是从技术层面上来说这句话也确实没有什么大的问题的,甚至可以说挺准确的,这里不得不说马斯克作为技术出身的创业者虽然成了企业家和富豪但是其对技术的理解和未来技术走向的嗅觉依旧是极为强悍的。......
  • X86架构与ARM架构的区别:
    原文链接:https://zhidao.baidu.com/question/208949741393495605.html?qbl=relate_question_11、含义不同:X86使用CISC(ComplexInstructionSetComputer,复杂指令集计算机)。ARM使用RISC(ReducedInstructionSetComputer,精简指令集计算机),ARM英文全称AdvancedRISCMachine。2、......
  • int和Integer的区别
    (1)Integer是int的包装类,int是基本数据类型(2)Integer变量必须实例化会才能使用,int变量则不用(3)Integer的默认值是null,int的默认值是0(4)Integer实际是对象的引用,newInteger()会生成一个指针指向此对象;int则直接存储数据值int和Integer的比较(1)Integeri=newInteger(100);Integ......
  • C语言中的printf和sprintf的用法及区别
    sprintf函数是C语言中用于格式化输出到字符串的函数。它的原型如下:intsprintf(char*buffer,constchar*format,[argument]…);str:指向存储输出结果的字符数组的指针。format:格式化字符串,包含要输出的文本和格式说明符。[argument]:可变参数列表,用于提供要插入格式化......
  • ArrayList的扩容机制以及ArrayList与LinkedList的区别
    ArrayList的扩容机制假设采用无参构造器来实列化ArrayList对象ArrayListarrayList=newArrayList();此时,arrayList的初始容量为零,当第一次调用add方法时,会触发扩容机制,容量扩容为10。此后,在调用add方法时,如果容量不足,则容量会扩容为当前容量的1.5倍。capcity=capacity......
  • vue一些基础概念,核心理念,框架和库的区别,MVC和MVVM的区别,展示数据的几种方法、v-bind、
    1、什么是vue,核心理念,为什么学习vue1(单页面应用程序)用于构建用户界面的渐进式框架,采用自底向上增量开发的设计2数据驱动视图,组件化开发3轻量级框架、简单易学、虚拟的DOM、数据视图结构分离下面展示一些内联代码片。下面是vue的代码框架分为三部分:1.引入vue.js;2......
  • [GPT] swoole的协程和golang的协程有什么区别,哪个更好
    Swoole的协程和Golang(Go语言)的协程(Goroutine)在概念上都是为了实现轻量级的并发编程,但它们在具体实现、使用方式和性能特点上有所不同:实现原理:Golang协程(Goroutine):Go语言从语言层面内置了对协程的支持。Goroutine是由Go运行时系统管理的轻量级线程,它基于M:N调度模型......
  • pageX|pageY、clientX |clientY、offsetX|offsetY的区别
    一、pageX|pageY当鼠标点击、按下、移动时触发,可获取到该值。pageX|pageY:以页面左上角为基准点,相对于页面来说的。【当前鼠标触发点,距离页面左上角的距离,不会因为页面的滚动条的改变而改变】二、clientX|clientY当鼠标点击、按下、移动时触发,可获取到该值。pageX|pageY:以浏览器......
  • TCL-{} 与“”的区别;$(), $, ${}的区别
    1.tcl中,{}对里面的各种特殊字符都不作处理,仅当做普通的字符串      “”对里面的各种分隔符不作处理,但是对换行符(\n);置换符($;[])会照常处理需要注意的是,在foreach中的{}里面的内容 变量置换和计算 操作仍会正常执行,是因为在foreach中{}作为其中的循......
  • CAD的ShowDialog与普通ShowDialog的区别
    记录解决的奇奇怪怪的bug今天在对form设置启动位置的时候一直设置不成功,后面才发生是AcadApp.ShowModalDialog的问题!我们知道CAD的ShowDialog会使新开的窗体在CAD上面所以正常开窗体都是用这个.今天我想把窗体开在我鼠标点的位置StartPosition=FormStartPosition.Ma......