`

ThreadPoolExecutor使用和思考(中)-keepAliveTime及拒绝策略

阅读更多

 

工作中多处接触到了ThreadPoolExecutor。趁着现在还算空,学习总结一下。

 

前记:

 

  1. jdk官方文档(javadoc)是学习的最好,最权威的参考。
  2. 文章分上中下。上篇中主要介绍ThreadPoolExecutor接受任务相关的两方面入参的意义和区别,池大小参数corePoolSize和maximumPoolSize,BlockingQueue选型(SynchronousQueue,LinkedBlockingQueue,ArrayBlockingQueue);中篇中主要聊聊与keepAliveTime这个参数相关的话题;下片中介绍一下一些比较少用的该类的API,及他的近亲:ScheduledThreadPoolExecutor
  3. 如果理解错误,请直接指出。
上篇文章 传送门 http://dongxuan.iteye.com/blog/901689

===============================神奇分割线==================================

通过上篇文章,我们可以总结出:ThreadPoolExecutor中额定的“工人”数量由corePoolSize决定,当任务数量超过额定工人数量时,将任务缓存在BlockingQueue之中,当发现如果连queue中也放不下时(可能是因为使用有界queue,也可能是使用SynchronousQueue),ThreadPoolExecutor会请求“老板”再派几个“工人”过来

接下来发生的事情有两种情况:
  1. 任务不再过来了 - keepAliveTime
  2. 任务仍然继续过来 - RejectedExecutionHandler

===============================神奇分割线==================================

keepAliveTime

jdk中的解释是:当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

有点拗口,其实这个不难理解,在使用了“池”的应用中,大多都有类似的参数需要配置。比如数据库连接池,DBCP中的maxIdle,minIdle参数。

什么意思?接着上面的解释,后来向老板派来的工人始终是“借来的”,俗话说“有借就有还”,但这里的问题就是什么时候还了,如果借来的工人刚完成一个任务就还回去,后来发现任务还有,那岂不是又要去借?这一来一往,老板肯定头也大死了。

合理的策略:既然借了,那就多借一会儿。直到“某一段”时间后,发现再也用不到这些工人时,便可以还回去了。这里的某一段时间便是keepAliveTime的含义,TimeUnit为keepAliveTime值的度量。

RejectedExecutionHandler

另一种情况便是,即使向老板借了工人,但是任务还是继续过来,还是忙不过来,这时整个队伍只好拒绝接受了。

RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机会。在ThreadPoolExecutor中已经默认包含了4中策略,因为源码非常简单,这里直接贴出来。

CallerRunsPolicy线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
 
这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。

AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException();
        }
 这种策略直接抛出异常,丢弃任务。

DiscardPolicy:不能执行的任务将被删除

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
 这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。

DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。这个策略需要适当小心。
设想:如果其他线程都还在运行,那么新来任务踢掉旧任务,缓存在queue中,再来一个任务又会踢掉queue中最老任务。

总结:

keepAliveTime和maximumPoolSize及BlockingQueue的类型均有关系。如果BlockingQueue是无界的,那么永远不会触发maximumPoolSize,自然keepAliveTime也就没有了意义。

反之,如果核心数较小,有界BlockingQueue数值又较小,同时keepAliveTime又设的很小,如果任务频繁,那么系统就会频繁的申请回收线程。
分享到:
评论
5 楼 huaxiuming 2014-01-10  
楼主总结真的很到位,很容易让人理解,什么时候出(下)啊
4 楼 baichh20110715 2013-05-28  
强烈希望 楼主可以更新下
3 楼 CHZiroy 2013-04-08  
理的策略:既然借了,那就多借一会儿。直到“某一段”时间后,发现再也用不到这些工人时,便可以还回去了。这里的某一段时间便是keepAliveTime的含义,TimeUnit为keepAliveTime值的度量。------------------------
貌似这里的keepAliveTime是指,一个线程在线程池中可以“发呆”的时间,也就是,在这个线程为某个任务服务完之后,可以等待keepAliveTime的时间,如果这个时间内没有新的任务来找它,那么它就被回收
2 楼 eimsteim 2012-05-17  
一年多了,看来是下不来咯
1 楼 fulink 2012-04-23  
博主,快更新:下

相关推荐

    ThreadPoolExecutor使用和思考

    ThreadPoolExecutor使用和思考

    java 线程池例子ThreadPoolExecutor

    Java 中的线程池是指一个容器,里面包含了多个线程,这些线程可以重复使用,以避免频繁创建和销毁线程的开销。ThreadPoolExecutor 是 Java 中一个非常重要的线程池实现类,它提供了一个高效、灵活的线程池解决方案。...

    ThreadPoolExecutor的使用和Android常见的4种线程池使用介绍

    ThreadPoolExecutor的使用和Android常见的4种线程池使用介绍

    JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用

    "JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用" JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecutor)使用是Java多线程编程中的一种重要概念。随着多线程编程的普及,线程池的使用变得...

    线程池之ThreadPoolExecutor.docx

    线程池是多线程编程中一种高效管理线程资源的方式,主要由Java的`ThreadPoolExecutor`类实现。线程池的工作机制在于控制线程数量,它会将任务放入队列,然后根据线程池的设定创建并启动线程执行这些任务。如果线程...

    JDK1[1].5中的线程池(ThreadPoolExecutor)使用简介

    JDK1[1].5中的线程池(ThreadPoolExecutor)使用简介

    ThreadPoolExecutor源码解析.pdf

    ThreadPoolExecutor是Java并发编程中重要的组件,它是ExecutorService接口的实现,用于管理和调度线程的执行。理解其源码有助于我们更好地控制并发环境下的任务执行,提高系统的效率和稳定性。 1. **线程池状态** ...

    ThreadPoolExecutor运转机制介绍

    如果当前线程池中的线程数量已经达到 `maximumPoolSize`,那么将会根据 `RejectedExecutionHandler` 的拒绝策略来处理新任务。 4. **线程的销毁**:当线程池中的线程数量大于 `corePoolSize` 时,那些超过 `...

    线程池ThreadPoolExecutor使用简介与方法实例

    线程池ThreadPoolExecutor使用简介与方法实例 线程池ThreadPoolExecutor是Java并发编程中...ThreadPoolExecutor是Java并发编程中一个非常重要的概念,它可以帮助我们更好地处理任务,从而提高系统的可扩展性和灵活性。

    线程池原理-ThreadPoolExecutor源码解析

    线程池原理-ThreadPoolExecutor源码解析 1.构造方法及参数 2.阻塞对列: BlockingQueue 3.线程工厂: DefaultThreadFactory 4.拒绝策略: RejectedExecutionHandler 5.执行线程 Executor

    Java线程池的拒绝策略实现详解

    最后,让我们通过一个简单的示例代码来演示如何使用ThreadPoolExecutor和RejectedExecutionHandler接口来实现线程池的拒绝策略。 ```java package com.cfang; import java.util.concurrent.BlockingQueue; import ...

    PyQt5中多线程模块QThread和线程池ThreadPoolExecutor解决PyQt5界面程序执行比较耗时操作无响应问题

    1.资源简介:PyQt5中使用多线程模块QThread解决了PyQt5界面程序执行比较耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题,采用线程池ThreadPoolExecutor解决了ping多个IP多任务耗时问题。...

    使用线程池ThreadPoolExecutor 抓取论坛帖子列表

    本文将详细讲解如何使用Java中的`ThreadPoolExecutor`来抓取论坛帖子列表,结合源码分析和实用工具的应用。 首先,我们要了解线程池的基本原理。线程池是由一组预先创建的线程组成的,这些线程可以复用,而不是每次...

    JDK之ThreadPoolExecutor源码分析1

    《JDK之...理解这些核心组件的工作方式,有助于我们在实际开发中更有效地使用线程池,优化系统的并发性能,并避免资源浪费。在后续的文章中,我们将进一步探讨这些细节以及线程池在不同状态下的行为。

    java 线程池实现多并发队列后进先出

    - **拒绝策略**:当线程池和工作队列都满时,新任务的处理策略。默认情况下,会抛出异常,但可以自定义策略如`AbortPolicy`、`CallerRunsPolicy`等。 4. **线程池的生命周期** - **初始化**:通过`new ...

    线程池ThreadPoolExecutor原理源码分析.md

    通过对 `execute()` 方法的深入分析,我们能够更全面地理解 `ThreadPoolExecutor` 在实际应用场景中的作用和意义。 线程池的设计不仅仅是为了提高程序的并发性能,更重要的是通过合理的配置和管理,避免因过度创建...

    线程池实例:使用Executors和ThreadPoolExecutor

    NULL 博文链接:https://bijian1013.iteye.com/blog/2284676

    ThreadPoolExecutor线程池的使用方法

    在ThreadPoolExecutor中,还有拒绝策略的概念,当线程池中的线程数大于maximumPoolSize时,线程池就不能在处理任何任务了,这时线程池会抛出异常。拒绝策略有四种:AbortPolicy、CallerRunsPolicy、...

    java ThreadPoolExecutor使用方法简单介绍

    主要介绍了java ThreadPoolExecutor使用方法简单介绍的相关资料,需要的朋友可以参考下

Global site tag (gtag.js) - Google Analytics