线程池: 简单理解,它就是一个管理线程的池子。
public ThreadPoolExecutor(int corePoolSize, //核心线程数,池中所保存的线程数,包括空闲线程。
int maximumPoolSize, //池中允许的最大线程数。
long keepAliveTime, //当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。即非核心线程空闲的最大存活时间
TimeUnit unit, //存活时间单位。
BlockingQueue workQueue, //执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
ThreadFactory threadFactory, //执行程序创建新线程时使用的工厂。
RejectedExecutionHandler handler) //由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。(拒绝策略)
提交一个任务,线程池里存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。
如果线程池核心线程数已满,即线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。
当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。
如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。
(1)AbortPolicy: 该策略抛出RejectedExecutionException,调用者捕获异常后进行处理。
(2)DiscartPolicy:当新任务无法加入到队列中时,该策略抛弃该任务。(直接丢弃任务)
(3)DiscardOldestPolicy:放弃最旧的未处理请求,然后重试 execute;如果执行程序已关闭,则会丢弃该任务。
(4)CallerRunsPolicy:直接在 execute 方法的调用线程中运行被拒绝的任务,即将任务回退到调用者。
一段会有异常的代码
可以看到,没有结果输出,但也没有异常抛出,这样无法感知到任务中出现的异常,所以要try/catch。
这样就捕获到异常。
Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future> 形式类型、并返回 null 作为底层任务的结果。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
提交任务
如果线程数少于核心线程,创建核心线程执行任务
如果线程数等于核心线程,把任务添加到LinkedBlockingQueue阻塞队列
如果线程执行完任务,去阻塞队列取任务,继续执行。
核心线程数和最大线程数大小一样
没有所谓的非空闲时间,即keepAliveTime为0
阻塞队列为无界队列LinkedBlockingQueue
LinkedBlockingQueue==(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列
//创建一个容量为 Integer.MAX_VALUE 的 LinkedBlockingQueue。
public LinkedBlockingQueue()
//创建一个具有给定(固定)容量的 LinkedBlockingQueue。 capacity - 队列的容量
public LinkedBlockingQueue(int capacity)
//创建一个容量是 Integer.MAX_VALUE 的 LinkedBlockingQueue,
//最初包含给定 collection 的元素,元素按该 collection 迭代器的遍历顺序添加。
public LinkedBlockingQueue(Collection<? extends E> c)
FixedThreadPool 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。
//需要时使用提供的 ThreadFactory 创建新线程。
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
/* 对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
调用 execute 将重用以前构造的线程(如果线程可用)。
如果现有线程没有可用的,则创建一个新线程并添加到池中。
终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线池不会使用任何资源。
注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
核心线程数为0
最大线程数为Integer.MAX_VALUE
阻塞队列是SynchronousQueue
非核心线程空闲存活时间为60秒
提交任务
因为没有核心线程,所以任务直接加到SynchronousQueue队列。
判断是否有空闲线程,如果有,就去取出任务执行。
如果没有空闲线程,就新建一个线程执行。
执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁。
SynchronousQueue==(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。
用于并发执行大量短期的小任务。
//安排在给定延迟后运行命令或者定期地执行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
最大线程数为Integer.MAX_VALUE
阻塞队列是DelayedWorkQueue
keepAliveTime为0
scheduleAtFixedRate() :按某种速率周期执行
scheduleWithFixedDelay():在某个延迟后执行
添加一个任务
线程池中的线程从 DelayQueue 中取任务
线程从 DelayQueue 中获取 time 大于等于当前时间的task
执行完后修改这个 task 的 time 为下次被执行的时间
这个 task 放回DelayQueue队列中
DelayQueue(延迟队列)是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。
周期性执行任务的场景,需要限制线程数量的场景
/*
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么需要,
一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,
并且在任意给定的时间不会有多个线程是活动的。
与其他等效的 newFixedThreadPool(1) 不同,
可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
核心线程数为1
最大线程数也为1
阻塞队列是LinkedBlockingQueue
keepAliveTime为0
提交任务
线程池是否有一条线程在,如果没有,新建线程执行任务
如果有,将任务加到阻塞队列
当前的唯一线程,从队列取任务,执行完一个,再继续取,一个人(一条线程)夜以继日地干活。
ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。
PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列;