java.util.concurrent ThreadPoolExecutor源码分析
实现的接口:Executor, ExecutorService
子类:ScheduledThreadPoolExecutor
这类为java线程池的管理和创建,其中封装好的线程池模型在Executors类中有实现。抛开Executors类中的实现,仅谈线程池模型ThreadPoolExecutor
线程池设计原理分析:官方文档
- Core and maximum pool sizes
- A
ThreadPoolExecutorwill automatically adjust the pool size (seegetPoolSize()) according to the bounds set by corePoolSize (seegetCorePoolSize()) and maximumPoolSize (seegetMaximumPoolSize()). When a new task is submitted in methodexecute(Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full. By setting corePoolSize and maximumPoolSize the same, you create a fixed-size thread pool. By setting maximumPoolSize to an essentially unbounded value such asInteger.MAX_VALUE, you allow the pool to accommodate an arbitrary number of concurrent tasks. Most typically, core and maximum pool sizes are set only upon construction, but they may also be changed dynamically usingsetCorePoolSize(int)andsetMaximumPoolSize(int). - On-demand construction
- By default, even core threads are initially created and started only when new tasks arrive, but this can be overridden dynamically using method
prestartCoreThread()orprestartAllCoreThreads(). You probably want to prestart threads if you construct the pool with a non-empty queue. - Creating new threads
- New threads are created using a
ThreadFactory. If not otherwise specified, aExecutors.defaultThreadFactory()is used, that creates threads to all be in the sameThreadGroupand with the sameNORM_PRIORITYpriority and non-daemon status. By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status, etc. If aThreadFactoryfails to create a thread when asked by returning null fromnewThread, the executor will continue, but might not be able to execute any tasks. Threads should possess the "modifyThread"RuntimePermission. If worker threads or other threads using the pool do not possess this permission, service may be degraded: configuration changes may not take effect in a timely manner, and a shutdown pool may remain in a state in which termination is possible but not completed. - Keep-alive times
- If the pool currently has more than corePoolSize threads, excess threads will be terminated if they have been idle for more than the keepAliveTime (see
getKeepAliveTime(TimeUnit)). This provides a means of reducing resource consumption when the pool is not being actively used. If the pool becomes more active later, new threads will be constructed. This parameter can also be changed dynamically using methodsetKeepAliveTime(long, TimeUnit). Using a value ofLong.MAX_VALUETimeUnit.NANOSECONDSeffectively disables idle threads from ever terminating prior to shut down. By default, the keep-alive policy applies only when there are more than corePoolSize threads. But methodallowCoreThreadTimeOut(boolean)can be used to apply this time-out policy to core threads as well, so long as the keepAliveTime value is non-zero. - Queuing
- Any
BlockingQueuemay be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:- If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
- If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
- If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
There are three general strategies for queuing:
- Direct handoffs. A good default choice for a work queue is a
SynchronousQueuethat hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies. Direct handoffs generally require unbounded maximumPoolSizes to avoid rejection of new submitted tasks. This in turn admits the possibility of unbounded thread growth when commands continue to arrive on average faster than they can be processed. - Unbounded queues. Using an unbounded queue (for example a
LinkedBlockingQueuewithout a predefined capacity) will cause new tasks to wait in the queue when all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.) This may be appropriate when each task is completely independent of others, so tasks cannot affect each others execution; for example, in a web page server. While this style of queuing can be useful in smoothing out transient bursts of requests, it admits the possibility of unbounded work queue growth when commands continue to arrive on average faster than they can be processed. - Bounded queues. A bounded queue (for example, an
ArrayBlockingQueue) helps prevent resource exhaustion when used with finite maximumPoolSizes, but can be more difficult to tune and control. Queue sizes and maximum pool sizes may be traded off for each other: Using large queues and small pools minimizes CPU usage, OS resources, and context-switching overhead, but can lead to artificially low throughput. If tasks frequently block (for example if they are I/O bound), a system may be able to schedule time for more threads than you otherwise allow. Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.
- Rejected tasks
- New tasks submitted in method
execute(Runnable)will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated. In either case, theexecutemethod invokes theRejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor)method of itsRejectedExecutionHandler. Four predefined handler policies are provided:- In the default
ThreadPoolExecutor.AbortPolicy, the handler throws a runtimeRejectedExecutionExceptionupon rejection. - In
ThreadPoolExecutor.CallerRunsPolicy, the thread that invokesexecuteitself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted. - In
ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped. - In
ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)
It is possible to define and use other kinds of
RejectedExecutionHandlerclasses. Doing so requires some care especially when policies are designed to work only under particular capacity or queuing policies. - In the default
- Hook methods
- This class provides
protectedoverridablebeforeExecute(Thread, Runnable)andafterExecute(Runnable, Throwable)methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, methodterminated()can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.If hook or callback methods throw exceptions, internal worker threads may in turn fail and abruptly terminate.
- Queue maintenance
- Method
getQueue()allows access to the work queue for purposes of monitoring and debugging. Use of this method for any other purpose is strongly discouraged. Two supplied methods,remove(Runnable)andpurge()are available to assist in storage reclamation when large numbers of queued tasks become cancelled. - Finalization
- A pool that is no longer referenced in a program AND has no remaining threads will be
shutdownautomatically. If you would like to ensure that unreferenced pools are reclaimed even if users forget to callshutdown(), then you must arrange that unused threads eventually die, by setting appropriate keep-alive times, using a lower bound of zero core threads and/or settingallowCoreThreadTimeOut(boolean).
Core and maximum pool size
- 为什么要设置maxinumPoolSize?情况1:maxinumPoolSize无限大,假设是同步队列,那么每一个task都会去请求一个线程,则可能耗尽系统资源。情况2:如果maxinumPoolSize不影响,那么就设置队列为无限大,例如LinkedBlockingQueue
java.util.concurrent ThreadPoolExecutor源码分析的更多相关文章
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...
- 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue
对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 《java.util.concurrent 包源码阅读》17 信号量 Semaphore
学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...
- java.util.concurrent.DelayQueue 源码学习
jdk1.8 DelayQueue,带有延迟元素的线程安全队列,当非阻塞从队列中获取元素时,返回最早达到延迟时间的元素,或空(没有元素达到延迟时间).DelayQueue的泛型参数需要实现Delaye ...
- 《java.util.concurrent 包源码阅读》11 线程池系列之ThreadPoolExecutor 第一部分
先来看ThreadPoolExecutor的execute方法,这个方法能体现出一个Task被加入到线程池之后都发生了什么: public void execute(Runnable command) ...
- 《java.util.concurrent 包源码阅读》12 线程池系列之ThreadPoolExecutor 第二部分
接着说worker线程是如何工作的.ThreadPoolExecutor有一个成员类叫Worker,所起到的作用就是线程池worker线程的作用. private final class Worker ...
随机推荐
- usaco Transformations
模拟就行.注意int arr[][]二维数组在定义时是二维数组,而函数传参时是指针.这意味着memset()的不同.传参时只能当作一维逐个memset. #include <iostream&g ...
- hdu number number number 斐波那契数列 思维
http://acm.hdu.edu.cn/showproblem.php?pid=6198 F0=0,F1=1的斐波那契数列. 给定K,问最小的不能被k个数组合而成的数是什么. 赛后才突然醒悟,只要 ...
- Android开源框架源码分析:Okhttp
一 请求与响应流程 1.1 请求的封装 1.2 请求的发送 1.3 请求的调度 二 拦截器 2.1 RetryAndFollowUpInterceptor 2.2 BridgeInterceptor ...
- ubuntu下安装CAJ阅读器
目录 1.ubuntu下wine的基本介绍 (1)wine的介绍 (2)wine的安装 (3)exe文件的安装 (4)exe程序的卸载 (6)wine的基本使用 2.CAJ阅读器的安装 (1)首先放上 ...
- 【洛谷p1403 】【AHOI2005】约数研究
(有种失踪人口回归的感觉) 约束研究[传送门] (不过好像没有人注意到我这个蒟蒻) 好的不管它啦 最近学数论比较多,所以可能会有好多好多的数论题???(不存在的) 行吧上算法标签: 数论 数论 ...
- python基础之列表以及切片等操作
列表 定义: 能装对象的对象,列表能放大量的数据,各种类型,且列表内的数据是可以修改保存的,常用 [ ] 去表示,每一项数据之间用逗号隔开 1.列表的索引与切片 1.1 索引 与字符串的索引几乎一致, ...
- Ubuntu深度学习环境搭建 tensorflow+pytorch
目前电脑配置:Ubuntu 16.04 + GTX1080显卡 配置深度学习环境,利用清华源安装一个miniconda环境是非常好的选择.尤其是今天发现conda install -c menpo o ...
- 两个约束下的dp问题
洛谷P1510 分析:本质上还是一个01背包,将体力当做重量,体积当做价值.配上滚动数组 即dp[j]代表在体力耗费为j时最大能搬运多少体积的石头,当dp[j]>v时就说明存在满足情况的解,这样 ...
- Java中遍历实体类(处理MongoDB)
在实际过程中,经常要将实体类进行封装,尤其是处理数据库的过程中:因此,对于遍历实体类能够与数据库中的一行数据对应起来. 我是使用的环境是Spring boot,访问的数据库时MongoDB 实体类遍历 ...
- Oracle中事务处理控制用法
oracle 事物控制包括 COMMINT ROLLBACK SAVEPOINT avepoint是事务内部允许部分rollback的标志符.因为事务中对记录做了修改,我们可以在事务中创建savepo ...