java中的线程(3):线程池类 ThreadPoolExecutor「线程池的类型、参数、扩展等」
官方文档: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
1.简介
public class ThreadPoolExecutor extends AbstractExecutorService
ExecutorService
that executes each submitted task using one of possibly several pooled threads, normally configured using Executors
factory methods.
Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor
also maintains some basic statistics, such as the number of completed tasks.
2.Executors工厂类
构造线程池类的方法
To be useful across a wide range of contexts, this class provides many adjustable parameters and extensibility hooks. However, programmers are urged to use the more convenient Executors
factory methods
Executors.newCachedThreadPool()
(unbounded thread pool, with automatic thread reclamation),Executors.newFixedThreadPool(int)
(fixed size thread pool)Executors.newSingleThreadExecutor()
(single background thread), that preconfigure settings for the most common usage scenarios.
Otherwise, use the following guide when manually configuring and tuning this class:
3.构造线程池的参数
3.1 Core and maximum pool sizes
A ThreadPoolExecutor
will automatically adjust the pool size (see getPoolSize()
) according to the bounds set by corePoolSize (see getCorePoolSize()
) and maximumPoolSize (see getMaximumPoolSize()
). When a new task is submitted in method execute(java.lang.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 as Integer.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 using setCorePoolSize(int)
and setMaximumPoolSize(int)
.
3.2 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()
or prestartAllCoreThreads()
.
You probably want to prestart threads if you construct the pool with a non-empty queue.
3.3 Creating new threads
New threads are created using a ThreadFactory
. If not otherwise specified, a Executors.defaultThreadFactory()
is used, that creates threads to all be in the same ThreadGroup
and with the same NORM_PRIORITY
priority and non-daemon status. By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status, etc. If a ThreadFactory
fails to create a thread when asked by returning null from newThread
, 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.
3.4 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(java.util.concurrent.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 method setKeepAliveTime(long, java.util.concurrent.TimeUnit)
. Using a value of Long.MAX_VALUE
TimeUnit.NANOSECONDS
effectively disables idle threads from ever terminating prior to shut down. By default, the keep-alive policy applies only when there are more than corePoolSizeThreads. But method allowCoreThreadTimeOut(boolean)
can be used to apply this time-out policy to core threads as well, so long as the keepAliveTime value is non-zero.
3.5 Queuing 当核心线程用完时,再添加任务时加到queue中
Any BlockingQueue
may 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
SynchronousQueue
that 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
LinkedBlockingQueue
without 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.
3.6 Rejected tasks 拒绝任务的4个策略类
New tasks submitted in method execute(java.lang.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, the execute
method invokes the RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor)
method of its RejectedExecutionHandler
.
Four predefined handler policies are provided:
- In the default
ThreadPoolExecutor.AbortPolicy
, the handler throws a runtimeRejectedExecutionException
upon rejection. - In
ThreadPoolExecutor.CallerRunsPolicy
, the thread that invokesexecute
itself 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 RejectedExecutionHandler
classes. Doing so requires some care especially when policies are designed to work only under particular capacity or queuing policies.
4.Hook methods
This class provides protected
overridable beforeExecute(java.lang.Thread, java.lang.Runnable)
and afterExecute(java.lang.Runnable, java.lang.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, method terminated()
can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.
5.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(java.lang.Runnable)
and purge()
are available to assist in storage reclamation when large numbers of queued tasks become cancelled.
6.Finalization
A pool that is no longer referenced in a program AND has no remaining threads will be shutdown
automatically. If you would like to ensure that unreferenced pools are reclaimed even if users forget to call shutdown()
, 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 setting allowCoreThreadTimeOut(boolean)
.
7.Extension example.扩展示例
Most extensions of this class override one or more of the protected hook methods. For example, here is a subclass that adds a simple pause/resume feature:
class PausableThreadPoolExecutor extends ThreadPoolExecutor { private boolean isPaused; private ReentrantLock pauseLock = new ReentrantLock(); private Condition unpaused = pauseLock.newCondition(); public PausableThreadPoolExecutor(...) { super(...); } protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); pauseLock.lock(); try { while (isPaused) unpaused.await(); } catch (InterruptedException ie) { t.interrupt(); } finally { pauseLock.unlock(); } } public void pause() { pauseLock.lock(); try { isPaused = true; } finally { pauseLock.unlock(); } } public void resume() { pauseLock.lock(); try { isPaused = false; unpaused.signalAll(); } finally { pauseLock.unlock(); } } }
java中的线程(3):线程池类 ThreadPoolExecutor「线程池的类型、参数、扩展等」的更多相关文章
- Java中多线程的使用(超级超级详细)线程池 7
Java中多线程的使用(超级超级详细)线程池 7 什么是线程池? 线程池是一个容纳多个线程的容器,线程池中的线程可以重复使用,无需反复创建线程而消耗过多的资源 *使用多线程的好处: 1.降低消耗,减少 ...
- Java中多线程的使用(超级超级详细)线程安全原理解析 4
Java中多线程的使用(超级超级详细)线程安全 4 什么是线程安全? 有多个线程在同时运行,这些线程可能会运行相同的代码,程序运行的每次结果和单线程运行的结果是一样的,而且其他变量的值也和预期的值一样 ...
- java中只能有一个实例的类的创建
Java中,如果我们创建一个类,想让这个类只有一个对象,那么我们可以 1:把该类的构造方法设计为private 2:在该类中定义一个static方法,在该方法中创建对象 package test; / ...
- java 中操作字符串都有哪些类?(未完成)它们之间有什么区别?(未完成)
java 中操作字符串都有哪些类?(未完成)它们之间有什么区别?(未完成)
- 【Java 多线程】Java线程池类ThreadPoolExecutor、ScheduledThreadPoolExecutor及Executors工厂类
Java中的线程池类有两个,分别是:ThreadPoolExecutor和ScheduledThreadPoolExecutor,这两个类都继承自ExecutorService.利用这两个类,可以创建 ...
- java中volatile关键字的含义--volatile并不能做到线程安全
在Java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...
- 【JAVA中String、StringBuffer、StringBuilder类的使用】
一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: public class Strin ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- Java中操作时间比较好用的类
项目中经常用到日期的操作,包括日期的格式化.下面是几个比较常用的工具类. import java.text.SimpleDateFormat; import java.util.Date; impor ...
随机推荐
- 如何处理与开发有争议的Bug?
工作中,测试人员有时会遇到类似的问题:提交了一份软件缺陷报告,可由于某种原因,无论是开发人员还是开发经理就是不愿修改程序.应如何处理这类问题呢?我认为,当对报告出现分歧意见后,测试工程师应首先做如下 ...
- C6678 srio communication via Switch
First, I don't often give praise for support but I must say Travis, Karthik and Derek from TI have b ...
- 如何将一个用utf-8编码的文本用java程序转换成ANSI编码的文本
jdk有一个关于UTF-8的bug所以加了一句 br.skip(1); bugID: http://bugs.java.com/view_bug.do?bug_id=4508058 public st ...
- 策略与计费控制(PCC)流程与信令流程
该文为3GPP TS23.203-be0 条款6-7译文 策略与计费控制(PCC)流程[^4] IP-CAN 会话有三种显著的场景: 无网关控制会话需求,不会出现网关控制建立 需要网关控制会话支持:B ...
- jQuery bind() live()
<script type="text/javascript"> $(document).ready(function () { /*$('.clickme').live ...
- C#ADO.NET基础二
DataAdapter的使用,批量增删改 1.使用DataAdapter查询 private void Select2() { try { using (SQLiteConnection conn = ...
- markdown syntax
Markdown 语法 转载自https://zh.mweb.im/markdown.html 首先应该了解的 每一个 Markdwon 使用者都应该了解的,是 Markdown 最基本的版本,也就是 ...
- 为什么 kubernetes 天然适合微服务 (3)
此文已由作者刘超授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验 四.Kubernetes 本身就是微服务架构 基于上面这十个设计要点,我们再回来看 Kubernetes,会发现 ...
- 「BJOI2012」连连看
题目链接 戳我 \(Solution\) 我们首先进行拆点操作,将每个点都拆成\(x\)和\(y\),将满足条件的两个点连起来就好了(记得要将\(x\)连\(y'\)的同时要将\(y\)联向\(x'\ ...
- c++实现多叉树树形显示(适合家谱的显示)
多叉树(左兄弟右孩子二叉树)的树形显示 核心代码 void positionadd(Multiway_tree*root, int n) { if (!root)return; Multiway_tr ...