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 ...
随机推荐
- 框架中如何根据fileupload工具包实现文件上传功能
工具包 Apache-fileupload.jar – 文件上传核心包. Apache-commons-io.jar – 这个包是fileupload的依赖包.同时又是一个工具包. 代码 servle ...
- v-for
在实际的项目中,我们很多时候会碰到将JSON数据中的数组或对象渲染出列表之类的元素.在Vue中,提供了一个 v-for的指令,可以渲染列表. 组件和v-for 在自定义组件里,你可以像任何普通元素一样 ...
- MongoDB存储
mongo DB #定义数据库,文件为config.py mongo_url='loclhost'//数据库地址 mongo_DB='DB_name'//数据库名称 mongo_TABEL='tabe ...
- 使用telnet模拟邮件的收发
smtp协议是一个简单的邮件传输协议,利用它我们可以将邮件发送给别人,这里将通过telnet这个程序利用smtp协议从网易向gmail发送一封邮件 基本步骤如下: 1.使用telnet连接smtp服务 ...
- 函数模版和主函数分别在.h .cpp中(要包含.cpp)
Complex.h #pragma once #include<iostream> using namespace std;//这句还必须加,要不然致错,不懂为啥呢 template &l ...
- Redis与memchache对比
Redis是NOSQL系统之一,它是一个key-value存储系统.和Memcache类似,但很大程度补偿了Memcache的不足,它支持存储的value类型相对更多,包括string.list.se ...
- CF-413E-线段树
http://codeforces.com/problemset/problem/413/E 给出一个2*N的格子图,每个格子要么是障碍要么是空地,M次询问(A,B)之间的最短距离. 采用分治的思想, ...
- 灵活运用 SQL SERVER FOR XML PATH 转
灵活运用 SQL SERVER FOR XML PATH FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些 ...
- Linux下使用mail发送邮件
邮件常常是Linux下监控报警手段之一.Linux下的mail命令可以方便,快速的完成发送邮件.下面以CentOS为例 1.安装 [root@vm8028 ~]# mail -bash: mail: ...
- MongoDB 教程(二):MongoDB 简介
概述: MongoDB 旨在为WEB应用提供可扩展.高性能的数据存储解决方案. MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成. MongoDB 文档类似于 ...