本文转载自微信公众号「怀梦追码」,作者水目沾 。转载本文请联系怀梦追码公众号。
网站建设哪家好,找成都创新互联!专注于网页设计、网站建设、微信开发、重庆小程序开发、集团企业网站建设等服务项目。为回馈新老客户创新互联还提供了淮南免费建站欢迎大家使用!
线程池的作用
池化技术是一种很常见的计算机技术,主要是为了复用和提高性能,如内存池、连接池、对象池等。线程池也不例外,他的主要作用如下:
JDK 在并发包中为我们定义了一套 Executor 框架,帮助开发人员有效地进行线程控制,有基础的线程池类、有线程池工厂,但是最最重要还是 ThreaPoolExecutor,也是面试中最常问的知识点。本文重点介绍 ThreaPoolExecutor 的原理。
线程池的参数说明
- ThreaPoolExecutor(
- int corePoolSize,
- long keepAliveTime,
- TimeUnit unit,
- BlockingQueue
workQueue, - ThreadFactory threadFactory,
- RejectedExecutionHandler handler)
- )
ThreaPoolExecutor 参数的含义如下
以上参数中 workQueue、threadFactory、handler 相对复杂,需要单独介绍,下面主要介绍下 ThreadFactory 和 RejectedExecutionHandler
1. 线程工厂:ThreadFactory
线程池中的线程都由 TrheadFactory 定义的线程工厂来创建,它是一个接口只有 Thread newThread(Runnable r) 方法,用来创建线程。虽然创建 ThreadPoolExecutor 的时候可以不指定该参数,但是阿里巴巴编码规约建议最好指定该参数,有以下几个好处:
2. 拒绝策略:RejectedExecutionHandler
当线程池线程数量达到 maxPoolSize 大小时,再提交新的任务会执行拒绝策略,JDK 定义了四种拒绝策略:
以上四种拒绝策略都继承了接口 RejectedExecutionHandler 并实现该接口的 rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法。如果以上四种拒绝策略都满足不了你的需求,可以自定义拒绝策略,继承接口 RejectedExecutionHandler 并实现方法即可。
线程池的调度逻辑
ThreaPoolExecutor 对提交的任务处理逻辑如下图,
1. 提交任务时:
2. 任务进行中时:
当队列中的任务已经执行完,部分线程开始空闲,非核心线程会在空闲后的 keepAliveTime 的时间内自行销毁。
而空闲核心线程是否退出取决于线程池的另一个参数 allowCoreThreadTimeOut 。当配置为 true 的时候,即使是核心线程,超时也会退出。
线程池的生命周期
线程池同线程一样也有自己的生命周期,包括 RUNNING、SHUTDOWN、STOP、TIDYING 和 TERMINATED 五种状态,他们的转换关系如下图,并且这些转换时不可逆的。
1. RUNNING
该状态是线程池的工作状态,能够接受新任务以及对接受的任务进行处理。线程池的初始状态,即线程创建成功后就处理此状态。
2. SHUTDOWN
关闭状态,线程池不再接受新的任务,但是能继续处理提交到线程池中的任务。线程状态 RUNNING 的情况下调用 shutdown() 方法进入该状态。
3. STOP
停止状态,线程池不接受新的任务,也不处理阻塞队列中的任务,同时会中断正在执行任务的线程。在线程处于 RUNNING 或者 SHUTDOWN 状态下调用 shutdownNow() 方法进入该状态。
4. TIDYING
所有任务都销毁了,workCount 为 0,会自动从 RUNNING 或者 STOP 状态转化为 TIDYING 状态。在转换过程中会调用 terminated() 方法,ThreadPoolExecutor 类的 ternimated() 方法为空,如果想在线程池变成 TIDYING 的时候有所处理,可以重载该方法。
线程池在 SHUTDOWN 状态下,阻塞队列为空并且执行任务为空时转换为 TIDYING 状态;线程池在 STOP 状态下,执行的任务为空时转换为 TIDYING 状态。
5. TERMINATED
结束状态,线程池的最终状态,该状态的线程池不会再有任何操作。线程池执行 terminated() 方法后处于该状态。
JDK 四种线程池
了解 ThreaPoolExecutor 的基本原理后再来看看 JDK 在 Executors 中为开发人员定义的四个线程池工厂方法,其实它们内部调用的是 ThreaPoolExecutor,只是使用了不同的参数,下面来了解下它们的特性。
newFixedThreadPool() 方法:该方法返回一个固定线程池数量的线程,提交任务时如果线程池中有空闲线程,则立即执行,没有则新的任务会被缓存在一个任务队列中,它创建线程池的代码如下:
- public static ExecutorService newFixedThreadPool(int nthread) {
- return new ThreadPoolExecutor(nthread,
- nthread,
- 0L,
- TimeUnit.MILLSECCONDS,
- new LikedBlockingQueue
()) - }
newSingleThreadExecutor() 方法:该方法返回只有一个线程的线程池,如果多余的任务提交到线程池,则被提交到任务队列中。它创建线程池代码如下:
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1,
- 1,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue
())); - }
newCachedThreadPool() 方法:该方法返回一个可根据实际情况调整线程数的线程池,它的核心线程数为 0 ,线程总数为 Integer.MAX_VALUE ,队列采用的是 SynchronousQueue,这样即使线程满,任务也不能提交到队列中。
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue
()); - }
newScheduledThreadPool():该方法一个固定长度的线程池,并且以延迟或者定时的方式去执行任务。它的队列使用 DelayedWorkQueue,所以任务必须继承 Delay 接口。
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
- return new ScheduledThreadPoolExecutor(corePoolSize);
- }
- public ScheduledThreadPoolExecutor(int corePoolSize) {
- super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
- new DelayedWorkQueue());
- }
分享名称:Java 并发之线程池
链接分享:http://www.shufengxianlan.com/qtweb/news36/491386.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联