import java.util.Date;
import java.util.concurrent.*;
/**
* Created by kodulf on 2017/4/11.
*/
public class ThreadPoolTest {
public static void main(String[] args){
Test test1 = new Test("1");
Test test2 = new Test("2");
Test test3 = new Test("3");
Test test4 = new Test("4");
Test test5 = new Test("5");
Test test6 = new Test("6");
Test test7 = new Test("7");
Test test8 = new Test("8");
Test test9 = new Test("9");
/**
*
*
*
线程池的优点:简单的来说就是节省资源
1:就像是洗澡,如果每一个人都是在自己家里面洗澡,那么每个人都需要开太阳能,都需要热水,例如如果是1000个人,那么就是需要消耗1000*每个人的资源,1000*1度电,=1000度电
但是如果大家一起去浴室洗澡,有一个大池子,那么可以有很多人一起洗澡,这个时候需要消耗的资源其实还是一直都是那么多,
例如这个浴室每天的耗电量是800度,那么如果数量是1000个,那么就会节省200度电,如果数量是2000,那么可能会比800度多一点例如1000度,但是也会比2000度电少很
首先需要注意的是
例如上面的Test 是继承了Thread 的线程,它并没有使用.start去启动,而是使用的executorService.execute(test1);
所以test1 只是一个任务,真正执行的是是线程池里面的线程。
鲜仁澡堂,草莓口味好,散芬草香,
鲜仁澡堂,x线程,r,任务,澡堂节省资源
草莓口味好,cmkwh,corePoolSize, maximumPoolsize,keepAliveTime,workQueue,handle
散芬草香,sfc,newSingleThreadExecutor();newFixedThreadPool(int i);newCachedThreadPool();newScheduleThreadPool();
联系上面来说,newSingleThreadExecutor 任务之间没有任何联系,
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* 保存在池中的线程的数量,即使这些线程他们已经idle空闲了,除非设置了allowCoreThreadTimeOut
* 需要的核心员工多少人,即使他们没有事情做也是会让他们在那边的。
*
* @param maximumPoolSize the maximum number of threads to allow in the pool
*
* 线程池中最大允许的线程的数量
* 最大允许的员工的数量
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* 千万要记住:默认的,这个保持活动的政策只有在线程的数量超过了核心线程的数量的时候才起作用,但是如果方法allowCoreThreadTimeOut(boolean)可以被用来设置这个time-out的政策给核心的线程
* 简单的来说,其实就是,如果当前的员工数量超过了我核心的员工的数量,如果你多长时间不干活了就把你辞职了,但是需要注意的是这里的worker,其实是线程池中的线程,并不是被执行的任务
* 当线程的数量大于核心线程的数量的时候,这个keepAlivetime就是超出的idle的线程最多保存多少时间了
*
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* 这个queue 是用来在任务被执行前hold这个任务的,这个queue 只有在任务是被execute 方法提交的时候才会调用的
* queue 其实就相当于是需要处理的事情,像是银行里面就是等待办理业务的人,像是工厂里等待处理的元件,公司待处理的文件
*
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* 处理当这个因为thread 的边界或者是queue的capacities 达到了最大值了execution 被blocked,
* 有四中hanlder的政策被提供:
* 1:在默认的ThreadPoolExecutor.AbortPolicy,这个handler 在reject的时候抛出一个运行时的RejectedExecutionException 的异常
* 2:在ThreadPoolExecutor.CallerRunsPolicy,这个thread 触发execute 本身去运行这个task。
* 这提供了一个简单的反馈控制机制,将减慢新任务提交的速度。
* 3:在ThreadPoolExecutor.DiscardPolicy,一个任务如果不能够被运行,那么就会被简单的丢弃了
* 4:在ThreadPoolExecutor.DiscardOldestPolicy,如果executor 没有被关闭,在这个work queue 最上面的的任务将会被丢弃,其实就是最旧未使用的,然后这个execution 将会回退
* (这个可以又失败,调用另一次重复)
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue} is null
*/
//得到一个只有一个线程的线程池的对象,任务是顺序被执行的,执行完过一个任务再执行下一个任务
// alive-time out 是0秒钟,默认的,这个保持活动的政策只有在线程的数量超过了核心线程的数量的时候才起作用,而这了核心线程数量和最大线程数量是一样的所以这里不会起作用的
//注意后面的是LinkedBlockingQueue<Runnable> 就是一个无边界的queue,可以添加任意数量的任务,但是需要注意的是这些任务之间不要有任何的联系
//ExecutorService executorService = Executors.newSingleThreadExecutor();
//Executors.newFixedThreadPool调用的是new Executors.FinalizableDelegatedExecutorService(
// new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
// 得到一个有固定的线程数的线程对象,任务数量和线程数量相同时,任务被同时执行,任务数量大于线程数量时
// 多出来的任务会等待已经创建的线程空闲时被执行,(其实就是上一个任务执行了,线程就可以执行其他的任务了)
// 核心线程和线程的最大数量是一样的,
// alive-time out 是0秒钟,默认的,这个保持活动的政策只有在线程的数量超过了核心线程的数量的时候才起作用,而这了核心线程数量和最大线程数量是一样的所以这里不会起作用的
// 使用的是LinkedBlockingQueue<Runnable>,就是一个无边界的queue,可以添加任意数量的任务,但是需要注意的是这些任务之间不要有任何的联系
// 注意fixed 的翻译是限定的意思
// ExecutorService executorService = Executors.newFixedThreadPool(2);
//return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
//创建缓冲的线程池对象,自身会创建一定数量的线程,当线程数量大于任务数量是,会自动的销毁空闲的线程
//当任务数量增加时,会增加线程的数量
// 核心线程数为0,最大线程数量为Integer.MAX_VALUE,大概是20亿左右的,相当于是无限大的线程数量了,
// 等待的时间是60 秒钟,就是1分钟,这个是每一个线程在idel的时候都会等待1分钟,然后自动的销毁的
// 注意这里的queue是SynchronousQueue 是同步的queue,这些被执行的任务之间内部是有联系的才会使用这个SynchronousQueue的
//ExecutorService executorService = Executors.newCachedThreadPool();
//new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
//创建数量无限的线程池对象,空闲的线程也不会被销毁
// 核心数量为设置的核心的数量,最大的线程数量是Integer.MAX_VALUE,相当于是无限的
// keep-alive的只是0 NANOSECONDS,这个
//ExecutorService executorService = Executors.newScheduledThreadPool(3);
//super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new ScheduledThreadPoolExecutor.DelayedWorkQueue());
// ThreadPoolExecutor executorService = new ThreadPoolExecutor(2,2,10L,TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.AbortPolicy());
/**
这个ThreadPoolExecutor 实现了 AbstractExecutorService,AbstractExecutorService 实现了接口 ExecutorService;
class ThreadPoolExecutor implements AbstractExecutorService
class AbstractExecutorService implements ExecutorService
*/
/**
http://docs.oracle.com/javase/8/docs/api/
一个ExecutorService 会可能会使用线程池中的多个线程中的一个去执行每一个被提交的task
默认的使用Executors的工厂类的方法去创建配置。
线程池解决了两个不同的问题:
他们常常能够改进性能当执行大的数量的异步任务的时候,通过减少每个任务的开销。
并且他们提供了一个绑定和管理资源,包括线程threads,还有在执行一个集合的任务的时候消耗的资源
每一个ThreadPoolExecutor 同时强化了一些基本的数据统计,例如已经完成的任务数量
An 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.
为了能够在广泛的上下文中使用,这个类提供了需要可修改的参数和可扩展的。
然后,开发者还是强烈的建议使用一些方便的Executors工厂类方法,例如Executors.newCachedThreadPool(没有边界的线程池,),
Executors.newFixedThreadPool(int)(固定的长度的线程池),Executors.newSingleThreadExecutor()(单个)
常用的场景里面就可以使用这些配置好了前期的工厂方法。或者是使用下面的guide 去手动的配置
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)
and 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:
核心和最大的池子
Core and maximum pool sizes
一个线程池会自动的适应池子的长度,根据设置的corePoolSize(核心池的size)和maximumPoolSize(最大的池子的size)
当一个新的task(或者说是new的新的thread)放到execute(Runnable) 里面执行的时候
如果这个时候线程池里面的线程的数量小于核心池的数量的时候,那么会在线程池里面新建一个新的thread去处理请求,即使线程池里面其他的正在工作的线程已经是idle的状态了
如果这个时候线程池里面的线程的数量大于核心池的数量但是小于最大线程池的数量的时候,除非queue已经满了才会去创建一个新的thread。
通过设置核心线程池的数量和最大线程池的数量相等,那么你创建了一个固定大小的线程池
通过设置最大的线程池为一个无限的值,例如Integer.MAX_VALUE,你允许线程池去适应任意数量的concurrent task
大多数的情况,核心的线程池的数量和最大线程池的数量是在创建的时候设置的,也是可以通过方法setCorePoolSize(int) 和 setMaximumPoolSize(int)去修改的。
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(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).
按需的构造方法
默认的情况,即使核心的threads 只有在新的task到达了才会被初始化创建并且启动,
但是这个可以通过使用prestartCoreThread() 和 prestartAllCoreThreads()两个方法来进行手动的重写。
如果你构造的线程池有一个非空的queue,你可能想要预启动threads。
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.
创建新的threads
通过ThreadFactory可以去创建新的threads。如果没有特殊的情况,一个Executors.defaultThreadFactory()会被使用,
它将会一相同的ThreadGroup和相同的NORM_PRIORITY和non-daemon的状态去创建threads。
通过提供不同的ThreadFactory,你可以修改thread的名字,thread的group,priority,daemon状态等等
如果ThreadFactory 没有成功的去创建一个thread,这个时候返回的是null。
这个executor执行者会继续,但是可能不能够执行任何task。
线程应该拥有"modifyThread"修改thread的运行时的权限
如果worker threads 或者其他的正在使用线程池的线程threads没有拥有这个运行时权限,
那么service 可能会被降级,配置的修改可能不能够即时的起作用,
并且一个关闭的线程池可能在一个状态,这个状态终结是可能的,但是并没有完成
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.
保持活动的时间,(如果你多长时间没有事情做了,那么我就要把你开除了)
如果线程池当前有笔核心线程数量多的线程,超出的线程如果已经是idle并且超过了keepAliveTime的时间了,那么将会被终结
这个提供了一个方法在线程池不是被激活使用的时候减少资源消耗。
如果线程池变成更加活跃以后,新的threads会被构造出来。
这个参数可以通过setKeepAliveTime(long, TimeUnit)手动的修改
使用Long.MAX_VALUE() TimeUnit.NANOSECONDS(纳秒) 的值有效的将空闲的threads在终结之前关闭,就是说不可能被关闭的
默认的,这个保持活动的政策只有在线程的数量超过了核心线程的数量的时候才起作用
但是如果方法allowCoreThreadTimeOut(boolean)可以被用来设置这个time-out的政策给核心的线程,
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 method setKeepAliveTime(long, 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 corePoolSize threads.
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.
队列
任何的BlockingQueue可能会被用于传送和持有提交的任务.
这个queue的使用需要和线程池的size 一起,
如果少于核心线程池数量的线程正在执行,那么Executor 经常更愿意添加一个新的thread而不是从queue中获取
如果是大于等于这个核心线程池的数量的时候,那么Executor 进场会愿意将这个请求放在queue中,而不是添加一个新的thread
如果一个请求不能够被添加到queue中,那么一个新的thread将会被创建,除非是这个会超出了最大的线程数量,在这种情况下,这个任务会被rejected
洗面有三种常见的queue的场景:
1:Direct handoffs(直接切换)
给work queue 的一个好的默认的选择是异步的queue (SynchronousQueue) 它会将tasks 传递给threads 而不是直接持有他们
这样,一个想要假如queue的task如果当前没有可以运行的thread,那么将会失败。所以呢,一个新的thread 将会被创建
这个policy 避免了当处理很多的内部有联系的请求的死锁,
直接奇幻通常需要 没有设置最大的线程数量去避免reject 新的提交的task
2: Unbounded queues.无边界的queue
使用额一个为绑定的queue(例如LinkedBlockingQueue,这里面没有定义capcity)
当核心新城池中的线程达到了数量了,并且正在运行busy的时候,需要将新的task在queue中进行等待
也即是说,没有大于核心线程数量的线程还是会百创建(这个最大的线程数不会再起作用了)
这个在每一个线程都是独立的时候比较适合,所以任务不会影响其他的任务的执行。
例如,一个网页的server。当这个类型的queue可以有效的平滑的处理瞬间的突发的请求,
它允许unbounded work queue 有不断的进行正在的可能心,当命令的平均到达速度比他们可以处理的快
3: Bounded queues. 有边界的queue
一个有边界的queue(例如一个ArrayBlockingQueue),可以通过设置有限的最大的线程池的数量来帮助避免资源疲惫,但是会比较难的去管理和控制
queue的size的大小和最大池的长度可能会相互交易:
使用很大的queue和很小的线程池最小cpu使用,os 资源,和上下文切换的开销,
但是会导致人为低吞吐量。如果任务常常block(例如如果他们i/o 绑定)
系统可能会去schedule计划时间给更多的threads 比你允许的多。使用小的queue 通常运去大的线程池的size,
这个会让cpus 更娇繁忙,但是会遇到不可接受的计划开销,这个也会降低吞吐量
Queuing
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:
1: 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.
2: 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.
3: 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.
被拒绝的tasks
通过execute(Runnable)来提交的新的任务在Executor被关闭了的时候,会被reject
同时如果Executor 使用有限的范围给最大的线程数量和queue的容量,并且饱和了时候,也会被reject
不管是上面的两种方法中的哪一种,execute 执行方法会触发 RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor)方法里面的 RejectedExecutionHandle
有四中hanlder的政策被提供:
1:在默认的ThreadPoolExecutor.AbortPolicy,这个handler 在reject的时候抛出一个运行时的RejectedExecutionException 的异常
2:在ThreadPoolExecutor.CallerRunsPolicy,这个thread 触发execute 本身去运行这个task。
这提供了一个简单的反馈控制机制,将减慢新任务提交的速度。
3:在ThreadPoolExecutor.DiscardPolicy,一个任务如果不能够被运行,那么就会被简单的丢弃了
4:在ThreadPoolExecutor.DiscardOldestPolicy,如果executor 没有被关闭,在这个work queue 最上面的的任务将会被丢弃,其实就是最旧未使用的,然后这个execution 将会回退
(这个可以又失败,调用另一次重复)
有可能去定义和使用其他RejectedExecutionHandler类型的类,
做这些需要一些仔细,特别是policy 已经被设置好了去在特定的capcity和queuing policies
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, the execute method invokes the RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor)
method of its RejectedExecutionHandler.
Four predefined handler policies are provided:
1: In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
2: In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task.
This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.
3: In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
4: 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.
挂钩方法
这个类提供了可以冲洗饿的beforeExecute 和afterExecute的方法,他们在执行任务之前和执行execution的task之后会被执行。
这些可以被操纵执行的环境,(其实就是进行一些环境的配置)
例如,重新初始化ThreadLocals,集合一些统计,或者是添加log的入口
还有,方法terminated()也可以被重写去执行一些特殊的processing 这个process 需要在Executor 全部结束后执行的
如果hook 或者回调方法抛出了异常,内部的worker threads 可能会变成fail或者突然结束
Hook methods
This class provides protected overridable beforeExecute(Thread, Runnable) and afterExecute(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, method terminated() 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 巩固
方法getQueue() 允许访问当前的queue 为了监控和debug的方便。
使用这个方法为了任何目的都是强烈不建议的。
两个提供了的方法,remove(Runnable)和purge()可以被用来在大量的queue的任务变成cancell的时候帮助存储回收
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) and purge() are available to assist in storage reclamation when large numbers of queued tasks become cancelled.
定型
一个线程池如果不再在任何program中被提及并且没有任何的线程在执行将会被自动的shutdown。
如果你想要去保证未被提及的pools被回收即使用户忘了调用shutdown(),
那么你必须安排那些不再使用的threads最后die,通过设置合理的keep-alive times,给0个核心线程池设置一个lower的边界或者设置FallowCoreThreadTimeOut(boolean)
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).
扩展的例子:
大多数的扩展会重写一个或者多个protected的hook 方法。
例如下面的添加了一个子类,它又pause和resume的特征
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();
}
}
}
还可以再看一下这个博客:http://www.cnblogs.com/exe19/p/5359885.html
*/
//ExecutorService executorService = Executors.newSingleThreadExecutor();//执行的最慢
ExecutorService executorService = Executors.newFixedThreadPool(10);//根据这个size的不同,越小执行的越慢,越大执行的越快
//ExecutorService executorService = Executors.newCachedThreadPool();//执行的最快,同时执行完1分钟之后,就会关闭这个线程池了,可以看它的方法如下就指导了
//ExecutorService executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());//执行的最快
Date date = new Date();
executorService.execute(test1);
executorService.execute(test2);
executorService.execute(test3);
executorService.execute(test4);
executorService.execute(test5);
executorService.execute(test6);
executorService.execute(test7);
executorService.execute(test8);
executorService.execute(test9);
//需要自己手动的去关闭,如果自己不手动的关闭,它是不会自己关闭的
//executorService.shutdown();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 当前executorService.isShutdown?"+executorService.isShutdown()+" executorService.isTerminated?"+executorService.isTerminated());
}
//System.exit(0);
}
}).start();
}
static class Test extends Thread{
String id;
Test(String id){
this.id = id;
}
@Override
public void run() {
int num = 100;
if (id.equals("2")) {
num = 122;
}
for (int i = 0; i < num; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " ---" + id + "--- " + i);
}
}
}
}