目录
监控线程池的运行状态
需要关注ThreadPoolExecutor中的四个方法
- Shutdown():启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。
- ShutdownNow():尝试停止所有主动执行的任务,停止等待任务的处理,并返回正在等待执行的任务列表。
- beforeExecutor(Thread t, Runnable r):在给定的线程中执行给定的Runnable之前调用方法
- afterExecutor(Runnable r, Throwable t):完成指定Runnable的执行后调用方法。
代码实例
- 监控shutdown时任务的执行情况以及执行时间
1.自定义ThreadPoolExecutor
package com.nieyp.customThreadPoolExecutor;
import com.nieyp.existException.ObjectUncaughtExceptionHandler;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ExecutorUtil extends ThreadPoolExecutor {
private ConcurrentHashMap<String, Date> startTimes;
private String poolName;
public ExecutorUtil(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, String poolName) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new ExecutorUtil.EventThreadFactory(poolName));
this.poolName = poolName;
this.startTimes = new ConcurrentHashMap<>();
}
//线程池关闭的统计:已经执行的任务,正在执行的任务,为执行的任务
@Override
public void shutdown() {
System.out.println(String.format(this.poolName + "Going to shutDown. Executed tasks: %d" + "Running tasks: %d, Pending tasks: %d ",
this.getCompletedTaskCount(),
this.getActiveCount(),
this.getQueue().size()));
System.out.println(String.format(this.poolName + "Going to shutDown. Executed tasks: %d" + "Running tasks: %d, Pending tasks: %d ",
this.getCompletedTaskCount(),
this.getActiveCount(),
this.getQueue().size()));
System.out.println(String.format(this.poolName + "Going to shutDown. Executed tasks: %d" + "Running tasks: %d, Pending tasks: %d ",
this.getCompletedTaskCount(),
this.getActiveCount(),
this.getQueue().size()));
if (this.getQueue().size() > 5){
System.out.println("阻塞队列的任务数量大于5,需要重新设置线程池的参数");
}
super.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
System.out.println(String.format(this.poolName + "Going to shutdownNow. Executed tasks: %d" + "Running tasks: %d, Pending tasks: %d ",
this.getCompletedTaskCount(),
this.getActiveCount(),
this.getQueue().size()));
return super.shutdownNow();
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
startTimes.put(String.valueOf(r.hashCode()), new Date());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
Date startTime = startTimes.remove(String.valueOf(r.hashCode()));
Date endTime = new Date();
long diff = startTime.getTime() - endTime.getTime();
System.out.println(String.format("task running time: %d", diff));*/
}
public static ExecutorService newFixedThreadPool(int nThreads, String poolName){
return new ExecutorUtil(nThreads, nThreads, 0L, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>(), poolName);
}
//自定义线程工厂,一般默认即可
static class EventThreadFactory implements ThreadFactory{
private final ThreadGroup group;
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private static final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
EventThreadFactory(String poolName) {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = poolName + "-pool" + poolNumber.getAndIncrement() + "-thread";
}
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement());
if (thread.isDaemon()) {
thread.setDaemon(false);
}
if (thread.getPriority() != Thread.NORM_PRIORITY) {
thread.setPriority(Thread.NORM_PRIORITY);
}
return thread;
}
}
}
2.自定义Runnable
package com.nieyp.customThreadPoolExecutor;
public class Reading implements Runnable{
private String name;
private int count;
public Reading(String name, int count) {
this.name = name;
this.count = count;
}
@Override
public void run() {
while (count > 0){
System.out.println(Thread.currentThread().getName() + "reading" + name);
count--;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
3.启动类
public class Main {
public static void main(String[] args) {
Reading runnable01 = new Reading("Java编程思想", 3);
Reading runnable02 = new Reading("Spring实战", 3);
Reading runnable03 = new Reading("SpringBoot实战", 3);
Reading runnable04 = new Reading("Mysql权威指南", 3);
Reading runnable05 = new Reading("SpringCloud 实战", 3);
ExecutorService service = ExecutorUtil.newFixedThreadPool(10, "imooc-nieyp");
service.execute(runnable01);
service.execute(runnable02);
service.execute(runnable03);
service.execute(runnable04);
service.execute(runnable05);
}
}
4.在执行任务之前为每个线程增加异常拦截器
- 定义异常拦截器
public class ObjectUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread thread, Throwable throwable) { System.out.println("threadName:" + thread.currentThread().getName() + "出错,错误信息为:" + throwable.getMessage()); } }
- 重写ExecutorUtil中的beforeExecute,手动设置异常情况
public class Reading implements Runnable{
private String name;
private int count;
public Reading(String name, int count) {
this.name = name;
this.count = count;
}
@Override
public void run() {
//如果任务的name为Java编程思想则会抛出异常
if (name.equals("Java编程思想")){
throw new RuntimeException();
}
while (count > 0){
System.out.println(Thread.currentThread().getName() + "reading" + name);
count--;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
t.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
}
- 打印的信息
imooc-nieyp-pool1-thread3readingSpringBoot实战
imooc-nieyp-pool1-thread3readingSpringBoot实战
imooc-nieyp-pool1-thread3readingSpringBoot实战
imooc-nieyp-pool1-thread2readingSpring实战
imooc-nieyp-pool1-thread2readingSpring实战
imooc-nieyp-pool1-thread2readingSpring实战
imooc-nieyp-pool1-thread5readingSpringCloud 实战
imooc-nieyp-pool1-thread5readingSpringCloud 实战
imooc-nieyp-pool1-thread5readingSpringCloud 实战
imooc-nieyp-pool1-thread4readingMysql权威指南
imooc-nieyp-pool1-thread4readingMysql权威指南
imooc-nieyp-pool1-thread4readingMysql权威指南
threadName:imooc-nieyp-pool1-thread1出错,错误信息为:
java.lang.RuntimeException
at com.nieyp.customThreadPoolExecutor.Reading.run(Reading.java:15)//当前在beforeExecute方法中我们也可以根据Runnable中的name进行判断是否增加异常拦截器,因为线程池中的线程都是复用的,所以只给单个线程设置实际上没有什么作用,只是模拟这个点
@Override protected void beforeExecute(Thread t, Runnable r) { Reading r1 = (Reading) r; if (r1.getName().equals("Java编程思想")){ t.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler()); } }
线程池中的一个线程出现异常
1.抛异常出来并打印在控制台上 1.1,众所周知submit底层其实也是调用的execute,因此它也有异常只是处理方法不一样,它们的区别 如下 1.1.1,execute没有返回值。可以执行任务,但无法判断任务是否成功完成。——实现Runnable接口 1.1.2,submit返回一个future。可以用这个future来判断任务是否成功完成。——实现Callable接口 1.2,执行方式为execute:抛出异常显示在控制台 1.3,执行方式为submit:submit提交时异常被存储在线程结果信息中,当调用get方法是判断线程运行结果状态, 有异常就抛出存储的异常信息,因此submit运行异常我们只能用get方法来拿到 2.其他线程任务不受影响 3.异常线程会被回收 3.1先删掉线程又再调用创建线程的方法,所以异常线程不是被回收,而是被删除了再创建一个新的顶替了