一、什么是线程池?
当需要处理大量任务时,每次都新建线程会消耗大量的系统资源,降低程序效率。线程池则可以解决这个问题,它是一种先创建好若干个线程,放到一个“池”中,按需分配使用的技术。
二、为何需要监控线程池?
尽管线程池在处理任务上有优势,但是如果没有监控机制,在线程池中可能会遇到以下问题: 1、大量任务积压导致线程池中的线程耗尽,没有足够的线程处理新的任务,导致任务等待时间过长; 2、线程池中有无效线程或线程阻塞,占用系统资源,但是并没有发挥作用; 3、线程池中的线程没有明确地完成任务,没有及时释放资源。
三、如何监控线程池?
1、使用ThreadPoolExecutor类创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, //线程池中核心线程数
maxPoolSize, //线程池中最大线程数
keepAliveTime, //线程池中线程空闲保持时间
TimeUnit.MILLISECONDS, //线程池中线程空闲保持时间单位
workQueue, //阻塞队列,暂存等待执行的任务
threadFactory,//线程池中线程创建工厂
rejectHandler); //拒绝执行任务的处理器
2、添加线程池监控
可以通过扩展ThreadPoolExecutor类的beforeExecute
、afterExecute
和terminated
方法,对线程池进行监控。
(1)beforeExecute
在每个执行任务前会被调用,可以记录开始执行任务的时间,以及任务信息等。
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
taskStartTime.set(System.currentTimeMillis());
//记录任务信息等
}
(2)afterExecute
在每个执行任务后会被调用,可以记录任务执行结束时间,以及任务执行结果等。
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
long duration = System.currentTimeMillis() - taskStartTime.get();
//记录任务执行时间和结果等
}
(3)terminated
在线程池关闭后会被调用,可以记录线程池关闭的时间。
protected void terminated() {
super.terminated();
//记录线程池关闭时间等
}
四、如何优化线程池?
1、线程池大小的优化
线程池大小要根据实际场景来定,过大会浪费资源,过小会导致任务等待时间过长。可以根据工作负载进行动态调整,提高性能。
2、合理配置阻塞队列大小
阻塞队列越大,线程等待的时间就越长,因此需要根据实际情况来进行调整。
3、合理配置保持时间
保持时间过短会导致频繁地创建和销毁线程,因此需要根据线程池的实际情况来进行调整。
五、代码示例
1、线程池监控示例
public class MyThreadPoolExecutor extends ThreadPoolExecutor {
private ThreadLocal<Long> taskStartTime = new ThreadLocal<>();
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
taskStartTime.set(System.currentTimeMillis());
//记录任务信息等
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
long duration = System.currentTimeMillis() - taskStartTime.get();
//记录任务执行时间和结果等
}
@Override
protected void terminated() {
super.terminated();
//记录线程池关闭时间等
}
}
2、创建线程池示例
MyThreadPoolExecutor executor = new MyThreadPoolExecutor(
corePoolSize, //线程池中核心线程数
maxPoolSize, //线程池中最大线程数
keepAliveTime, //线程池中线程空闲保持时间
TimeUnit.MILLISECONDS, //线程池中线程空闲保持时间单位
workQueue, //阻塞队列,暂存等待执行的任务
threadFactory,//线程池中线程创建工厂
rejectHandler); //拒绝执行任务的处理器