一、为什么要使用线程
线程池提供了一种限制和管理资源(包括执行一个任务)。每个线程池还维护一些基本统计信息,例如已完成任务的数量。
使用线程池的好处:
二、如何创建线程池?
(1) ThreadPoolExecutor 创建线程池
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, handler);
创建线程池需要如下的参数:
也可以根据应用场景来实现 RejectedExecutionHandle 接口自定义策略。如记录日志或持久化存储不能处理的任务。
(2) Executor 创建线程池
a、newFixedThreadPool
FixedThreadPool 被称为可重用固定线程数的线程池。如下源代码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
FixedThreadPool 使用无界队列 LinkedBlockingQueue 作为线程池的工作队列(队列容量为 Integer.MAX_VALUE)。使用无界队列会造成如下影响:
b、newSingleThreadExecutor() 单线程线程池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
SingleThreadExecutor() 是使用单个 worker 线程的 Executor。单线程线程池,那么线程池中运行的线程数肯定是1。 workQueue 选择了无界的 LinkedBlockingQueue,那么不管来多少任务都排队,前面一个任务执行完毕,再执行队列中的线程。从这个角度讲,第二个参数 maximumPoolSize 是没有意义的,因为 maximumPoolSize 描述的是排队的任务多过 workQueue 的容量,线程池中最多只能容纳 maximumPoolSize 个任务,现在 workQueue 是无界的,也就是说排队的任务永远不会多过 workQueue 的容量,那 maximum 其实设置多少都无所谓了。
c、newCachedThreadPool
CachedThreadPool 是一个会根据需要创建新线程的线程池。如下源代码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
corePoolSize 被设置为 0;maximumPoolSize 被设置为 Integer.MAX_VALUE,即 maximumPool 是无界的。将 keepAliveTime 设置为 60L,表明空闲线程等待新任务的时间最长为 60s,超过后则会被终止。
CachedThreadPool 使用没有容量的 SynchronousQueue 作为线程池的工作队列,但是 maximumPool 确是无界的。这意味着,如果主线程提交任务的速度高于 maximumPool 中线程处理任务的速度时,CachedThreadPool 会不断创建新线程。极端情况下,CachedThreadPool 会因为创建过多的线程而耗尽 CPU 和内存资源。
第 4 种:newScheduledThreadPool
创建固定长度的线程池,且同时以延迟或者定时的方法来执行任务。
三、阻塞队列 BlockingQueue
该类主要提供了两个方法 put() 和 take(),前者将一个对象放到队列中,如果队列以及满了,就等待直到有空闲节点;与后者从 head 去一个对象,如果没有对象,就等待直到有可取的对象。
FixedThreadPool 与 Sing了ThreadPool 都是采用无界的 LinkedBlockingQueue 实现。LinkedBlockingQueue 中引入了两把锁 takeLock 和 putLock,显然分别是用于 take 操作和 put 操作的。即 LinkedBlockingQueue 入队和出队用的是不同的锁,那么 LinkedBlockingQueue 可以同时进行入队和出队操作,但是由于使用链表实现,所有查找速度会慢一些。
CachedThreadPool 使用的是 SynchronousQueue。
线程池对任务队列包括三种:有界队列、无界队列、同步移交。
原文:https://www.cnblogs.com/reformdai/p/11099978.html