一个线程池中的线程异常了,那么线程池会怎么处理这个线程?
首先进行模拟,
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
public class ExecutorsTest {
public static void main(String[] args) {
ThreadPoolTaskExecutor executorService = buildThreadPoolTaskExecutor();
executorService.execute(() -> sayHi("execute"));
Future<?> submit = executorService.submit(() -> sayHi("submit"));
try {
submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
private static void sayHi(String name) {
String printStr = "【thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "】";
System.out.println(printStr);
throw new RuntimeException(printStr + ",抛出异常!!");
}
private static ThreadPoolTaskExecutor buildThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();
executorService.setThreadNamePrefix("(ThreadTest)-");
executorService.setCorePoolSize(5);
executorService.setMaxPoolSize(10);
executorService.setQueueCapacity(1000);
executorService.setKeepAliveSeconds(30);
executorService.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executorService.initialize();
return executorService;
}
}
结果如下:
Exception in thread "(ThreadTest)-1" java.lang.RuntimeException: 【thread-name:(ThreadTest)-1,执行方式:execute】,抛出异常!
at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.sayHi(ExecutorsTest.java:25)
at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.lambda$main$0(ExecutorsTest.java:10)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
【thread-name:(ThreadTest)-1,执行方式:execute】
【thread-name:(ThreadTest)-2,执行方式:submit】
由结果可见
当执行方式是execute时,可以看到堆栈异常的输出。
当执行方式是submit时,堆栈异常没有输出。
-
当执行方式是executes时:
在java.util.concurrent.ThreadPoolExecutor#runWorker中抛出了异常:

在java.lang.ThreadGroup#uncaughtException进行了异常处理:

这个方法是JVM调用的,我们只需要指定我们想要的处理方式即可。
那我们怎么指定呢:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class test {
public static void main(String[] args) {
Runnable runnable = () -> {
throw new RuntimeException("runtimeEx");
};
//直接new Thread()的时候
Thread t = new Thread(runnable);
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("hahha=" + e.getMessage());
}
});
t.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程池的时候:
ExecutorService threadPool = Executors.newFixedThreadPool(2, r -> {
Thread temp = new Thread(r);
temp.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("hahhapool=" + e.getMessage());
}
});
return temp;
});
threadPool.execute(runnable);
}
}
运行结果:
hahha=runtimeEx
hahhapool=runtimeEx
-
当执行方式是submit时:

其本质也是调用了execute方法,所以它还是回到java.util.concurrent.ThreadPoolExecutor#runWorker方法:

不影响其他线程任务
ThreadPoolTaskExecutor executorService = buildThreadPoolTaskExecutor();
executorService.execute(() -> sayHi("execute"));
//executorService.submit(() -> sayHi("submit"));
Future<?> submit = executorService.submit(() -> sayHi("submit"));
try {
submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.execute(() -> sayHi("55"));
executorService.execute(() -> sayHi("execute1"));
executorService.execute(() -> sayHi("execute2"));
结果:
【thread-name:(ThreadTest)-2,执行方式:submit】
【thread-name:(ThreadTest)-5,执行方式:execute2】
Exception in thread "(ThreadTest)-3" java.lang.RuntimeException: 【thread-name:(ThreadTest)-3,执行方式:55】,抛出异常!
at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.sayHi(ExecutorsTest.java:35)
at cn.starcart.open.openapi.constants.remoteurl.ExecutorsTest.lambda$main$2(ExecutorsTest.java:25)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
【thread-name:(ThreadTest)-4,执行方式:execute1】
【thread-name:(ThreadTest)-1,执行方式:execute】
线程池中一个线程异常了后,不影响其他线程任务
大家注意线程名称这个细节:1,2,3,4,6。魔鬼都在细节里啊,这个点我下面会讲,先在这里把问题抛出来:我就纳闷了,怎么没有5啊?!
这个线程会被放回线程池为啥全错了?
我们去源码里面寻找答案:
让源码给出答案:
5号线程去哪里了?
new Worker()方法会告诉你:5去哪里了。
再配上这张由我这个灵魂画师亲自操刀画的图,一起食用,味道更佳:
现在我们知道为啥:我回答这个线程会被放回线程池为啥全错了吧。还附送你一个线程名称变化的细节,不客气,关注一下就好。
当一个线程池里面的线程异常后:
当执行方式是execute时,可以看到堆栈异常的输出。
当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常。
不会影响线程池里面其他线程的正常执行。
线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。
网友评论