[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 <tt>execute</tt> 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<Runnable>());}

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* <tt>nThreads</tt> 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<Runnable>());}

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* <tt>newFixedThreadPool(1)</tt> 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<Runnable>()));}

程序演示

  • LiftOff

    public class LiftOff implements Runnable {protected int countDown = 10; // Defaultprivate 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!") + ") ";}@Overridepublic 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 个线程,并交替执行。

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

  • 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 个线程,并交替执行。

  • 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 个线程。

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. 在运行时动态控制线程池的大小(Dynamic Thread Pool)

参考

iteye: Java 并发包中的几种 ExecutorService

stackoverflow: FixedThreadPool vs CachedThreadPool: the lesser of two evils

blogjava: 深入浅出多线程(4)对CachedThreadPool OutOfMemoryError问题的一些想法

结束

转载于:https://www.cnblogs.com/richaaaard/p/6599184.html

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

  1. 【Java 并发编程】线程池机制 ( ThreadPoolExecutor 线程池构造参数分析 | 核心线程数 | 最大线程数 | 非核心线程存活时间 | 任务阻塞队列 )

    文章目录 前言 一.ThreadPoolExecutor 构造参数 二.newCachedThreadPool 参数分析 三.newFixedThreadPool 参数分析 四.newSingleTh ...

  2. 【Java 并发编程】线程池机制 ( 线程池示例 | newCachedThreadPool | newFixedThreadPool | newSingleThreadExecutor )

    文章目录 前言 一.线程池示例 二.newCachedThreadPool 线程池示例 三.newFixedThreadPool 线程池示例 三.newSingleThreadExecutor 线程池 ...

  3. (转)Java并发编程:线程池的使用

    背景:线程池在面试时候经常遇到,反复出现的问题就是理解不深入,不能做到游刃有余.所以这篇博客是要深入总结线程池的使用. ThreadPoolExecutor的继承关系 线程池的原理 1.线程池状态(4 ...

  4. [转]Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  5. Java并发编程一线程池简介

    推荐:Java并发编程汇总 Java并发编程一线程池简介 为什么我们需要使用线程池? 我们知道线程是一种比较昂贵的资源,我们通过程序每创建一个线程去执行,其实操作系统都会对应地创建一个线程去执行我们的 ...

  6. Java并发编程一线程池的五种状态

    推荐:Java并发编程汇总 Java并发编程一线程池的五种状态 原文地址 Java多线程线程池(4)–线程池的五种状态 正文 线程池的5种状态:Running.ShutDown.Stop.Tidyin ...

  7. Java并发编程:线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  8. Java并发编程之线程池及示例

    1.Executor 线程池顶级接口.定义方法,void execute(Runnable).方法是用于处理任务的一个服务方法.调用者提供Runnable 接口的实现,线程池通过线程执行这个 Runn ...

  9. Java并发编程之线程池ThreadPoolExecutor解析

    线程池存在的意义 平常使用线程即new Thread()然后调用start()方法去启动这个线程,但是在频繁的业务情况下如果在生产环境大量的创建Thread对象是则会浪费资源,不仅增加GC回收压力,并 ...

  10. 《Java 并发编程》线程池

    <Java 并发编程>专栏索引

最新文章

  1. 经典再读 | NASNet:神经架构搜索网络在图像分类中的表现
  2. Leet Code OJ 4. Median of Two Sorted Arrays [Difficulty: Hard]
  3. 丢失日志文件的风险与对策
  4. 织梦首页html在哪儿,dedecms织梦首页去index.html
  5. 华为云电脑和马云无影比_阿里云打造未来电脑无影,却因为5G限制,很难达到普及...
  6. spring-data-jpa 使用
  7. 冯长根教授:博士生其实不是学生
  8. Magento教程 13:在Magento中设定联络表单的收件信箱
  9. Android自定义ImageView(二)——实现双击放大与缩小图片
  10. shell 脚本批量安装perl包
  11. 冒泡排序(数组排序不用Array.Sort)
  12. 不属于python第三方程序_安装 selenium 对于python而言属于一个第三方的模块
  13. html 必填设置,html如何设置必填项
  14. 零信任是一次绝地反击
  15. Promise回调地狱的拯救者
  16. QVGA、WVGA、VGA、WQVGA、SQVGA等几种手机分辨率扫盲!
  17. pf与ckf_基于CKF-PF算法在高速动车组定位中的应用研究
  18. 机器人自动化中的通讯手段
  19. 我的世界-01-从小型机到个人计算机的发展简史(上)
  20. onecloud的一次刷机自我小总结

热门文章

  1. 小程序的前端坑(持续更新)
  2. 企业网络推广期间影响企业网络推广自然排名的因素有哪些?
  3. 网站推广——网站推广专员面对新站收录展开多角度思考
  4. 网站优化上首页不算成功稳定排名才算
  5. sub在python中的意义_在python中,如何使用回复sub?
  6. 与或非逻辑符号_理解FPGA的基础知识——逻辑电路
  7. AS升级3.1 编译报错:The SourceSet 'instrumentTest' is not recognized by the Android Gradle Plugin.
  8. (转载)各Linux发行版本 网络配置文件
  9. ES等待任务——是master节点上的task任务
  10. 高斯混合模型Gaussian Mixture Model (GMM)——通过增加 Model 的个数,我们可以任意地逼近任何连续的概率密分布...