线程池中线程异常后:销毁还是复用?

一、一个线程池中的线程异常了,那么线程池会怎么处理这个线程?

需要说明,本文的线程池都是 java.util.concurrent.ExecutorService 线程池,本文将围绕验证,阅读源码俩方面来解析这个问题。

二、代码验证

2.1 验证 execute 提交线程池中

2.1.1 测试代码:

public class ThreadPoolExecutorDeadTest { 
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = buildThreadPoolExecutor();
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute-exception"));
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute"));
Thread.sleep(5000);
System.out.println("再次执行任务=======================");
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute"));
executorService.execute(() -> exeTask("execute"));
}
public static ExecutorService buildThreadPoolExecutor() {
return new ThreadPoolExecutor(5, 10, 30,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000),
new ThreadFactoryBuilder().setNameFormat("test-%s").build() ,
new ThreadPoolExecutor.CallerRunsPolicy());
}
private static void exeTask(String name) {
String printStr = "[thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "]";
if ("execute-exception".equals(name)) {
throw new RuntimeException(printStr + ", 我抛异常了");
} else {
System.out.println(printStr);
}
}
}

2.1.2 执行结果如下:

线程池中线程异常后:销毁还是复用?

2.1.3 结论:

execute 提交到线程池的方式,如果执行中抛出异常,并且没有在执行逻辑中catch,那么会抛出异常,并且移除抛出异常的线程,创建新的线程放入到线程池中。

2.2 验证 submit 提交线程池中

2.2.1 测试代码:


public class ThreadPoolExecutorDeadTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = buildThreadPoolExecutor();
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute-exception"));
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute"));
Thread.sleep(5000);
System.out.println("再次执行任务=======================");
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute"));
executorService.submit(() -> exeTask("execute"));
}
public static ExecutorService buildThreadPoolExecutor() {
return new ThreadPoolExecutor(5, 10, 30,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000),
new ThreadFactoryBuilder().setNameFormat("test-%s").build() ,
new ThreadPoolExecutor.CallerRunsPolicy());
}
private static void exeTask(String name) {
String printStr = "[thread-name:" + Thread.currentThread().getName() + ",执行方式:" + name + "]";
if ("execute-exception".equals(name)) {
throw new RuntimeException(printStr + ", 我抛异常了");
} else {
System.out.println(printStr);
}
}
}

2.2.2 执行结果如下:

线程池中线程异常后:销毁还是复用?

2.2.3 结论:

submit 提交到线程池的方式,如果执行中抛出异常,并且没有catch,不会抛出异常,不会创建新的线程。

三、源码解析

3.1 java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable)

线程池中线程异常后:销毁还是复用?

3.2 查看execute方法的执行逻辑java.util.concurrent.ThreadPoolExecutor#runWorker

线程池中线程异常后:销毁还是复用?

3.3 java.util.concurrent.ThreadPoolExecutor#processWorkerExit

线程池中线程异常后:销毁还是复用?

可以发现,如果抛出异常,会移除抛出异常的线程,创建新的线程。

3.4 为什么submit方法,没有创建新的线程,而是继续复用原线程?

还记得,我们在3.1的时候,发现submit也是调用了execute方法,但是在调用之前,包装了一层 RunnableFuture,那一定是在RunnableFuture的实现 FutureTask中有特殊处理了,我们查看源码可以发现。

线程池中线程异常后:销毁还是复用?
线程池中线程异常后:销毁还是复用?

但是,我们通过 java.util.concurrent.FutureTask#get(),就可以获取对应的异常信息。

四、总结

当一个线程池里面的线程异常后:

  • 当执行方式是 execute 时,可以看到堆栈异常的输出,线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。

  • 当执行方式是submit时,堆栈异常没有输出。但是调用 Future.get() 方法时,可以捕获到异常,不会把这个线程移除掉,也不会创建新的线程放入到线程池中。

以上俩种执行方式,都不会影响线程池里面其他线程的正常执行。

原文地址:https://zhuanlan.zhihu.com/p/689473823?utm_medium=social&utm_psn=1757116884241993728&utm_source=wechat_session


原文始发于微信公众号(醉鱼Java):线程池中线程异常后:销毁还是复用?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/262945.html

(0)
Java朝阳的头像Java朝阳

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!