博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Java并发编程(一)] 线程池 FixedThreadPool vs CachedThreadPool ...
阅读量:6242 次
发布时间:2019-06-22

本文共 6975 字,大约阅读时间需要 23 分钟。

[Java并发编程(一)] 线程池 FixedThreadPool vs CachedThreadPool ...

摘要

介绍 Java 并发包里的几个主要 ExecutorService 。

正文

CachedThreadPool

CachedThreadPool 是通过 java.util.concurrent.Executors 创建的 ThreadPoolExecutor 实例。这个实例会根据需要,在线程可用时,重用之前构造好的池中线程。这个线程池在执行 大量短生命周期的异步任务时(many short-lived asynchronous task),可以显著提高程序性能。调用 execute 时,可以重用之前已构造的可用线程,如果不存在可用线程,那么会重新创建一个新的线程并将其加入到线程池中。如果线程超过 60 秒还未被使用,就会被中止并从缓存中移除。因此,线程池在长时间空闲后不会消耗任何资源。

注意队列实例是:new SynchronousQueue

/**     * Creates a thread pool that creates new threads as needed, but     * will reuse previously constructed threads when they are     * available.  These pools will typically improve the performance     * of programs that execute many short-lived asynchronous tasks.     * Calls to execute will reuse previously constructed     * threads if available. If no existing thread is available, a new     * thread will be created and added to the pool. Threads that have     * not been used for sixty seconds are terminated and removed from     * the cache. Thus, a pool that remains idle for long enough will     * not consume any resources. Note that pools with similar     * properties but different details (for example, timeout parameters)     * may be created using {@link ThreadPoolExecutor} constructors.     *     * @return the newly created thread pool     */    public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue
()); }

FixedThreadPool

FixedThreadPool 是通过 java.util.concurrent.Executors 创建的 ThreadPoolExecutor 实例。这个实例会复用 固定数量的线程 处理一个 共享的无边界队列 。任何时间点,最多有 nThreads 个线程会处于活动状态执行任务。如果当所有线程都是活动时,有多的任务被提交过来,那么它会一致在队列中等待直到有线程可用。如果任何线程在执行过程中因为错误而中止,新的线程会替代它的位置来执行后续的任务。所有线程都会一致存于线程池中,直到显式的执行 ExecutorService.shutdown() 关闭。

注意队列实例是:new LinkedBlockingQueue

/**     * Creates a thread pool that reuses a fixed number of threads     * operating off a shared unbounded queue.  At any point, at most     * nThreads threads will be active processing tasks.     * If additional tasks are submitted when all threads are active,     * they will wait in the queue until a thread is available.     * If any thread terminates due to a failure during execution     * prior to shutdown, a new one will take its place if needed to     * execute subsequent tasks.  The threads in the pool will exist     * until it is explicitly {@link ExecutorService#shutdown shutdown}.     *     * @param nThreads the number of threads in the pool     * @return the newly created thread pool     * @throws IllegalArgumentException if {@code nThreads <= 0}     */    public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue
()); }

SingleThreadPool

SingleThreadPool 是通过 java.util.concurrent.Executors 创建的 ThreadPoolExecutor 实例。这个实例只会使用单个工作线程来执行一个无边界的队列。(注意,如果单个线程在执行过程中因为某些错误中止,新的线程会替代它执行后续线程)。它可以保证认为是按顺序执行的,任何时候都不会有多于一个的任务处于活动状态。和 newFixedThreadPool(1) 的区别在于,如果线程遇到错误中止,它是无法使用替代线程的。

/**     * Creates an Executor that uses a single worker thread operating     * off an unbounded queue. (Note however that if this single     * thread terminates due to a failure during execution prior to     * shutdown, a new one will take its place if needed to execute     * subsequent tasks.)  Tasks are guaranteed to execute     * sequentially, and no more than one task will be active at any     * given time. Unlike the otherwise equivalent     * newFixedThreadPool(1) the returned executor is     * guaranteed not to be reconfigurable to use additional threads.     *     * @return the newly created single-threaded Executor     */    public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue
())); }

程序演示

  • LiftOff

    public class LiftOff implements Runnable {        protected int countDown = 10; // Default        private static int taskCount = 0;        private final int id = taskCount++;        public LiftOff() {}        public LiftOff(int countDown) {            this.countDown = countDown;        }        public String status() {            return "Thread ID: [" + String.format("%3d", Thread.currentThread().getId()) + "] #" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + ") ";        }        @Override        public void run() {            while (countDown-- > 0) {                System.out.println(status());                Thread.yield();            }        }    }
  • CachedThreadPoolCase

    public class CachedThreadPoolCase {        public static void main(String[] args) throws InterruptedException {            ExecutorService exec = Executors.newCachedThreadPool();            for(int i = 0; i < 5; i++) {                exec.execute(new LiftOff());                Thread.sleep(10);            }            exec.shutdown();        }    }

    当 sleep 间隔为 5 milliseconds 时,共创建了 3 个线程,并交替执行。

    613455-20170322120530783-418548309.png

    当 sleep 间隔为 10 milliseconds 时,共创建了 2 个线程,交替执行。

    613455-20170322120605065-477297113.png

  • FixedThreadPoolCase

    public class FixedThreadPoolCase {        public static void main(String[] args) throws InterruptedException {            ExecutorService exec = Executors.newFixedThreadPool(3);            for (int i = 0; i < 5; i++) {                exec.execute(new LiftOff());                Thread.sleep(10);            }            exec.shutdown();        }    }

    无论 sleep 间隔时间是多少,总共都创建 3 个线程,并交替执行。

    613455-20170322120639518-1742226978.png

  • SingleThreadCase

    public class SingleThreadPoolCase {        public static void main(String[] args) throws InterruptedException {            ExecutorService exec = Executors.newSingleThreadExecutor();            for (int i = 0; i < 10; i++) {                exec.execute(new LiftOff());                Thread.sleep(5);            }            exec.shutdown();        }    }

    无论 sleep 间隔时间是多少,总共都只创建 1 个线程。

    613455-20170322120717658-197550206.png

FixedThreadPool 与 CachedThreadPool 特性对比

特性 FixedThreadPool CachedThreadPool
重用 FixedThreadPool 与 CacheThreadPool差不多,也是能 reuse 就用,但不能随时建新的线程 缓存型池子,先查看池中有没有以前建立的线程,如果有,就 reuse ;如果没有,就建一个新的线程加入池中
池大小 可指定 nThreads,固定数量 可增长,最大值 Integer.MAX_VALUE
队列大小 无限制 无限制
超时 无 IDLE 默认 60 秒 IDLE
使用场景 所以 FixedThreadPool 多数针对一些很稳定很固定的正规并发线程,多用于服务器 大量短生命周期的异步任务
结束 不会自动销毁 注意,放入 CachedThreadPool 的线程不必担心其结束,超过 TIMEOUT 不活动,其会自动被终止。

最佳实践

FixedThreadPool 和 CachedThreadPool 两者对高负载的应用都不是特别友好。

CachedThreadPool 要比 FixedThreadPool 危险很多。

如果应用要求高负载、低延迟,最好不要选择以上两种线程池:

  1. 任务队列的无边界:会导致内存溢出以及高延迟
  2. 长时间运行会导致 CachedThreadPool 在线程创建上失控

因为两者都不是特别友好,所以推荐使用 ThreadPoolExecutor ,它提供了很多参数可以进行细粒度的控制。

  1. 将任务队列设置成有边界的队列
  2. 使用合适的 RejectionHandler - 自定义的 RejectionHandler 或 JDK 提供的默认 handler 。
  3. 如果在任务完成前后需要执行某些操作,可以重载

    beforeExecute(Thread, Runnable) afterExecute(Runnable, Throwable)
  4. 重载 ThreadFactory ,如果有线程定制化的需求
  5. 在运行时动态控制线程池的大小()

参考

结束

转载地址:http://mmsia.baihongyu.com/

你可能感兴趣的文章
前后端导出/下载excel方法
查看>>
JVM之垃圾回收与内存动态分配
查看>>
Numpy中的广播原则/机制
查看>>
DOM编程系列之事件
查看>>
小程序加载svg图片
查看>>
JavaScript面向对象编程-多态
查看>>
sequelize 管理查询——一对一关联查询
查看>>
PHP下kafka的常用脚本实践
查看>>
AJAX
查看>>
百度地图绘制点、图形
查看>>
PHP 文件系统完全指南
查看>>
PyQt5,RadioButton
查看>>
js设计模式(二)-工厂模式
查看>>
前端技术周刊 2018-08-13:Web Components
查看>>
kube-proxy源码解析
查看>>
REM,你这磨人的小妖精!
查看>>
聊聊HystrixConcurrencyStrategy
查看>>
PHP多进程系列笔记(一)
查看>>
深析Vue双向数据绑定(MVVM模型)
查看>>
【跃迁之路】【485天】程序员高效学习方法论探索系列(实验阶段242-2018.06.05)...
查看>>