如果在系统中大量使用线程池,则有必要对线程池进行监控,方便在出现问题时,可以根据线程池的使用状态快速定位问题。可以根据线程池提供的参数进行监控,常用属性如下:
taskCount:线程池需要执行的任务数量
completedTaskCount:已完成的任务数量
largestPoolSize:线程池曾经创建过的最大线程数量,可以推测出是否达到corePoolSize和MaxinumPoolSize
getPoolSize:线程池的线程数量,只要不销毁,只增不减
getActiveCount:活动的线程总数
接下来展示的通过扩展线程池的方式监控状态:
1、继承线程池,重写beforeExecute、afterExecute、temninate等方法
package com.fc.provider;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 自定义线程池
*
* @author fc on 2018/4/27.
*/
public class ThreadPoolExecutorDef extends ThreadPoolExecutor {
/**
* 重写构造方法
*
* @param corePoolSize 核心线程数量
* @param maximumPoolSize 最大线程数量
* @param keepAliveTime 非核心线程闲置存活时间
* @param unit 时间单位
* @param workQueue 工作队列
* @param threadFactory 线程工厂
* @param handler 拒绝策略
*/
public ThreadPoolExecutorDef(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit,
BlockingQueue 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);
System.out.println(t.getName() + " run task thread : " + r.toString());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future>) {
try {
Object result = ((Future>)r).get();
System.out.println("callback:" + result.toString());
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t != null) {
System.out.println(t);
}
}
@Override
protected void terminated() {
super.terminated();
System.out.println("terminated...");
}
}
2、spring中注册bean,根据构造方法注入相关属性,如下所示:
3、junit中测试代码如下:
@Resource
private ThreadPoolExecutorDef threadPoolExecutorDef;
@Test
public void testRunTask() throws InterruptedException {
MyTask myTask = new MyTask();
for (int i = 0; i < NormalNumberConstant.INT_10; i++) {
threadPoolExecutorDef.execute(myTask);
}
Thread.sleep(2000);
System.out.println("lastest pool size : " + threadPoolExecutorDef.getLargestPoolSize());
System.out.println("pool size : " + threadPoolExecutorDef.getPoolSize());
LinkedBlockingQueue queue = (LinkedBlockingQueue)threadPoolExecutorDef.getQueue();
queue.forEach(System.out::println);
threadPoolExecutorDef.shutdown();
}
4、执行结果如下:
pool-2-thread-1 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
pool-2-thread-2 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825339996:Thread name:pool-2-thread-2
1524825339996:Thread name:pool-2-thread-1
pool-2-thread-3 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825339996:Thread name:pool-2-thread-3
pool-2-thread-4 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825339996:Thread name:pool-2-thread-4
pool-2-thread-5 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825339996:Thread name:pool-2-thread-5
pool-2-thread-3 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
pool-2-thread-4 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825340996:Thread name:pool-2-thread-4
pool-2-thread-2 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825340996:Thread name:pool-2-thread-2
pool-2-thread-1 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825340996:Thread name:pool-2-thread-1
pool-2-thread-5 run task thread : com.fc.common.ThreadPoolDemo$MyTask@68e6e5e0
1524825340996:Thread name:pool-2-thread-5
1524825340996:Thread name:pool-2-thread-3
lastest pool size : 5
pool size : 5
terminated...
5、threadFactoryNew为自定义的线程工厂,该类定义如下:
public class ThreadFactoryConsumer implements ThreadFactory {
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public ThreadFactoryConsumer() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "demo-pool-" +
POOL_NUMBER.getAndIncrement() +
"-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
6、MyTask为实现Runnable接口的线程对象,只执行输出并sleep1秒模拟执行时间
System.out.println(System.currentTimeMillis() + ":Thread name:"
+ Thread.currentThread().getName());