线程池的优点:
线程池创建的各个参数:
线程池中线程创建流程:
我们可以通过ThreadPoolExecutor创建一个线程池
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
1) corePoolSize: 当提交一个任务时(即使其他空闲核心线程也能够执行新任务),线程池会创建一个新线程来执行任务,等到corePoolSize个线程被创建了,就不再创建了。如果要额外创建,就要看后面的参数。如果调用了线程的prestartAllCoreThreads()
方法,线程池会提前创建并启动所有核心线程
2) maximumPoolSize: 线程池允许创建的最大线程数。如果队列满了,并且已经创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果使用了无界队列,该参数没什么效果
3) keepAliveTime: 线程池的工作线程空闲后,保持存活的时间。如果每个线程执行时间较短,可以将该值调大,提高线程利用率
4) unit: 时间单位
5) workQueue: 用于保存等待执行的任务的阻塞队列,可以选择以下几个阻塞队列:
* ArrayBlockingQueue: 是一个基于数组结构的有界阻塞队列,此队列按FIFO原则队元素进行排序
* LinkedBlockingQueue: 一个基于链表结构的阻塞,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
* SynchronousQueue: 一个不存储元素的队列。每个插入操作要必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列
* PriorityQueue: 一个具有优先级的无限阻塞队列
6) handler: RejectPolicy默认有四种:
* AbortPolicy,直接抛出异常
* DiscardPolicy,丢弃该任务,放弃处理
* CallerRunsPolicy,只用调用者线程执行任务
* DiscardOldestPolicy,丢弃队列里的队首元素
线程池提交任务有两个方法向线程池提交任务,分别为execute()和submit():
关闭线程池有两个方法,分别为shutdown()
和 shutdownNow()
共同点:
遍历线程池中的所有线程,然后逐个调用线程的interrupt()
方法来中断线程,所以无法响应中断的线程可能永远无法被终止。
不同点:
当任意一个关闭方法被调用时,isShutdown()方法就会返回true。当所有的任务关闭后,调用isTerminated()才会返回true。
具体要调用shutdown()
还是shutdownNow()
,需要根据具体业务来判断(通常调用shutdown()
)。如果任务不一定要执行完,可以用shutdownNow()
如何挑选:
注意:建议使用有界队列,因为如果线程池里的工作线程全部阻塞,任务挤压在线程池里,最终会导致整个系统不可用
通过扩展线程池进行监控。可以通过继承线程池来自定义线程池,重写线程池的beforeExecute()
, afterExecute()
, terminated()
方法,也可以在任务执行前、后执行一些代码来监控。
该篇主要了解了线程池的使用已经各个元素的含义以及监控时的优化。
原文:https://www.cnblogs.com/codeleven/p/10963128.html