【线程池】线程池的线程遇到异常后去哪里?怎么处理?

11 篇文章 0 订阅

1 四种解决任务代码抛异常的方案:

  • 在我们提供的Runnable的run方法中捕获任务代码可能抛出的所有异常,包括未检测异常
  • 使用ExecutorService.submit执行任务,利用返回的Future对象的get方法接收抛出的异常,然后进行处理(使用java.util.concurrent.FutureTask包装,实现call)
  • 重写ThreadPoolExecutor.afterExecute方法,处理传递到afterExecute方法中的异常
  • 为工作者线程设置UncaughtExceptionHandler,在uncaughtException方法中处理异常

要注意的是,使用最后一种方案时,无法处理以submit的方式提交的任务

 

1.1 第一种源码:异常会导致线程死亡,创建新的工作者加入线程池

 

 

 

1.2 第二种源码: 工作线程还是一样的,只是run方法是执行含有生命周期的Future对象,所以不会多次创建工作者

经过FutureTask包装!
public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

 

 

 

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
鸣谢 首先要感谢linus,给了我们一个可以自由翱翔的平台; 其次,要感谢网络上千万的linux/windows先行者,给予的有意或无意的指点和帮助; 再次,感谢陈皓兄的《跟我一起写makefile》,引导我走过了makefile的迷雾。后来发现于凤昌兄译的《GNU Make使用手册》,也有颇多受益。 背景 从2004年,我在一个公司作服务端软件的开发,要支持linux/windows平台,主要是为了容易维护,就设计、开发了这一套比较常用的类。 2005一直在windows下作IPTV的开发,在2006年底,又回到linux下作IPV6下IPTV的开发。在空闲时间,看看两年前的那些零散类文件,开始整理这些类成库,并写了简单的使用和测试范例,放在网上和朋友们共享。 由于早期的平台从windows98和VC6.0,redhat8.0,经历了些变迁,没有太多的时间再一一仔细测试,就用现在的windowsXP和VS.2003,Fedaro Core4.0作的测试。 主要是为了相互学习,希望能和朋友们共同进步!如有引用,请标明出处,会不胜感激!禁止商业性的书籍的引用!很多不良的作者,完全是在骗钱。 功能简介 通用于linux/windows平台C++的应用。 主要是对一些系统功能,进行了简洁封装。 主要有读写锁类, 线程类, 线程池类, 定时器类, socket1.1的封装类, ini文件类, txt文件类, 可删除内容的文件类, 查找文件类, 调试输出类, 字符串类, 同步的普通队列和优先级队列类, 智能指针和内存自动管理类,数据库类. 特别声明:因为环境限制,这次测试代码,没有测试数据库类。我以前也只是在PostgreSQL,SQL Server2000和Acess2000实际用过。如有朋友用到,请自行修改、测试。 这些类的风格,与个人习惯密切相关。推荐QT,跨平台的类库,还是不错的;ACE就太难使用了! 编译和运行: 1. windwos下,用vs2003打开pub下的test.sln文件,所有的测试程序和类库文件就载入,编译即可。其它程序引用库时,请选/MDd选项。 2. linux下,执行pub下的Makefile文件,编译即可。如果没有安装PostgreSql,数据库部分会编译不过。 关于inline函数 我写的这些类的函数,大部分是可以写成inline函数的,对性能提高也有很大的帮助。但是,GCC和VC的不同版本编译器的支持程度不同,可能会编译不过,所以就都没有为提高效率而写inline函数。依赖于编译器,对跨平台的程序来说,也比较麻烦! 不过,现在的硬件系统,对这些小小的性能提升,也感觉不出来的。 如有需要,请自行改写! 关于异常和错误处理 也是仁者见仁,智者见智! 习惯于C开发的朋友,大概喜欢函数错误时返回错误码。函数有返回值,就要处理,就使程序逻辑较为复杂,看去也比较的混乱。 我则喜欢用异常代替,主要是代码简洁和逻辑清晰。异常抛掷,会使流程很简洁,只显示执行正确时的流程,错误集处理 对于那些失败即意味着止的一个操作,我让其抛掷异常。如果是正常的分支流程,则用返回失败值。就我遇到的情况,大部分则为操作失败,调用的流程一般都要止的。 这个判断也是比较难下的。放在一个局部,异常可能导致操作止;但放在更上一层,则异常又可能是正确程序流程处理。 bug的反馈和修改支持 如果有重大的错误需要偶修正,请发到[email protected]的邮箱,尽量说明问题的现象,我会在一周内解决的(如果工作比较紧急的时候,不能即时就处理的)。
### 回答1: 如果需要关闭某个线程,可以通过断(interrupt)线程的方式终止它的执行。示例代码如下: ```java ExecutorService executor = Executors.newFixedThreadPool(10); Future<?> future = executor.submit(() -> { // 异步任务的代码 }); // 断正在执行的任务 future.cancel(true); ``` 在调用submit()方法后,会返回一个Future对象,表示异步任务的执行结果。可以通过调用该对象的cancel()方法来任务的执行。如果传入的参数为true,则会尝试任务的执行,否则会等待任务执行完成。 需要注意的是,任务的执行并不会立即生效,而是需要在异步任务自行判断线程断状态,然后在合适的时机终止任务的执行。示例代码如下: ```java ExecutorService executor = Executors.newFixedThreadPool(10); Future<?> future = executor.submit(() -> { while (!Thread.currentThread().isInterrupted()) { // 异步任务的代码 } }); // 断正在执行的任务 future.cancel(true); ``` 在异步任务,可以通过判断Thread.currentThread().isInterrupted()的返回值来判断线程是否被断。如果返回true,则表示线程断,需要终止任务的执行。在任务的代码,可以通过抛出InterruptedException异常来终止任务的执行,示例代码如下: ```java ExecutorService executor = Executors.newFixedThreadPool(10); Future<?> future = executor.submit(() -> { try { while (!Thread.currentThread().isInterrupted()) { // 异步任务的代码 } } catch (InterruptedException e) { // 终止任务的执行 } }); // 断正在执行的任务 future.cancel(true); ``` ### 回答2: 在使用Java异步服务时,线程池的正确关闭是非常重要的。如果线程池不能正常关闭,将导致线程暴增,从而导致系统资源耗尽,甚至宕机。以下是一个示例代码,展示了如何正确关闭线程池。 ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class AsynchronousServiceExample { private ExecutorService threadPool; public void startService() { // 初始化线程池 threadPool = Executors.newFixedThreadPool(10); // 启动异步任务 for (int i = 0; i < 100; i++) { threadPool.submit(() -> { // 异步任务的具体逻辑 // ... }); } } public void stopService() { // 关闭线程池并等待任务执行完成 threadPool.shutdown(); // 请求线程池关闭 try { if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) { // 等待线程池任务执行完毕,最多等待60秒 threadPool.shutdownNow(); // 强制关闭线程池 if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) { // 如果线程池仍未关闭,则输出错误日志 System.err.println("线程池未能正常关闭"); } } } catch (InterruptedException e) { // 捕获线程异常 threadPool.shutdownNow(); // 如果线程等待时被断,则强制关闭线程池 Thread.currentThread().interrupt();// 重新设置线程断状态 } } } ``` 在上述示例代码,我们首先利用`Executors.newFixedThreadPool()`方法创建线程池,大小为10,并启动了100个异步任务。当需要关闭线程池时,调用`threadPool.shutdown()`方法来请求线程池关闭。然后,使用`threadPool.awaitTermination()`方法等待线程池任务执行完成,最多等待60秒。如果超过60秒仍有任务没有执行完毕,使用`threadPool.shutdownNow()`方法强制关闭线程池。最后,通过判断线程池是否成功关闭来决定是否输出错误日志。为了处理线程异常,我们在`awaitTermination()`方法和`shutdownNow()`方法之后重新设置了线程断状态,以确保程序的稳定性。 ### 回答3: 当使用线程池时,可能会遇到线程暴增的问题。为了解决这个问题,可以采取以下步骤来关闭线程: 步骤1: 停止向线程池提交新的任务。这可以通过调用线程池的shutdown方法来完成,该方法将不再接受新任务,并尝试将所有已提交但未执行的任务完成。 步骤2: 等待线程池任务执行完成。可以使用awaitTermination方法来等待,该方法将会等待指定时间,直到所有任务都执行完成或者超时。 步骤3: 如果在等待时间内,线程池任务仍未执行完成,可以使用shutdownNow方法来止所有未执行的任务。该方法将会发送断信号给线程池线程,使其尽快停止执行。 下面是一个示例代码,演示了如何使用线程池来执行异步任务,并关闭线程池: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class ThreadPoolExample { public static void main(String[] args) { // 创建线程池,指定最大线程数 ExecutorService executor = Executors.newFixedThreadPool(10); // 提交任务线程池执行 for (int i = 0; i < 100; i++) { executor.execute(new Worker()); } // 停止向线程池提交新的任务 executor.shutdown(); try { // 等待线程池任务执行完成,最多等待1小时 if (!executor.awaitTermination(1, TimeUnit.HOURS)) { // 在等待时间内,任务未执行完成,进行处理 executor.shutdownNow(); // 等待线程池任务止 if (!executor.awaitTermination(1, TimeUnit.MINUTES)) { System.err.println("线程池未能完全停止"); } } } catch (InterruptedException e) { // 发生异常,进行处理 executor.shutdownNow(); } } private static class Worker implements Runnable { @Override public void run() { // 执行具体的任务逻辑 // ... } } } ``` 上述示例代码,首先创建了一个固定大小的线程池,然后使用execute方法提交任务线程池执行。接着调用shutdown方法停止向线程池提交新的任务,然后使用awaitTermination方法等待线程池任务执行完成。如果等待时间超过指定的超时时间(在示例为1小时),则调用shutdownNow方法止未执行的任务。最后,再次等待线程池任务止,如果超时,则打印一条警告信息。如果在任何等待期间发生了InterruptedException异常,则会调用shutdownNow方法止未执行的任务

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自驱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值