7、多线的异常处理
来源:互联网 发布:淘宝抢购手机 编辑:程序博客网 时间:2024/04/28 12:47
在普通的单线程程序中,捕获异常只需要通过try … catch … finally …代码块就可以了。那么,在并发情况下,比如在父线程中启动了子线程,如何正确捕获子线程中的异常,从而进行相应的处理呢?
常见错误
很简单嘛,直接在父线程启动子线程的地方try … catch一把就可以了,其实这是不对的。
原因分析
让我们回忆一下Runnable接口的run方法的完整签名,因为没有标识throws语句,所以方法是不会抛出checked异常的。
至于RuntimeException这样的unchecked异常,由于新线程由JVM进行调度执行,如果发生了异常,也不会通知到父线程。
子线程中发生了异常,如果没有任何类来接手处理的话,是会直接退出的,而不会记录任何日志。
所以,如果什么都不做的话,是会出现子线程任务既没执行成功,也没有任何日志提示的“诡异”现象的。
1、子线程中try… catch…
最简单有效的办法,就是在子线程的执行方法中,把可能发生异常的地方,用try … catch … 语句包起来。
public class ChildThread implements Runnable { public void run() { doSomething1(); try { // 可能发生异常的方法 exceptionMethod(); } catch (Exception e) { // 处理异常 System.out.println(String.format("handle exception in child thread. %s", e)); } doSomething2(); }}
主线程不能捕获到子线程的异常
package Thread.Exection;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ExeceptionThread implements Runnable { @Override public void run() { throw new RuntimeException(); } public static void main(String[] args) { try { ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new ExeceptionThread()); } catch (Exception e) { System.out.println("exeception has handled"); } }}
输出:
“`java
Exception in thread “pool-1-thread-1” java.lang.RuntimeException
at Thread.Exection.ExeceptionThread.run(ExeceptionThread.java:10)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
# 2、为线程设置“未捕获异常处理器”UncaughtExceptionHandler具体做法可以是以下几种:- Thread.setUncaughtExceptionHandler设置当前线程的异常处理器;- Thread.setDefaultUncaughtExceptionHandler为整个程序设置默认的异常处理器;1. 如果当前线程有异常处理器(默认没有),则优先使用该UncaughtExceptionHandler类;2. 如果当前线程所属的线程组有异常处理器,则使用线程组的UncaughtExceptionHandler;3. 使用全局默认的DefaultUncaughtExceptionHandler;如果都没有的话,子线程就会退出。**自定义异常处理器**```java/** * @author LF * @description 自定义的多线程异常处理 * @date 2017/11/23 23:09 */public class MyThreadException implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(String.format("handle exception in child thread. %s", e)); throw new RuntimeException(e); }}<div class="se-preview-section-delimiter"></div>
定义使用该异常处理器的线程
public class ExceptionThread implements Runnable { static { /** * 设置所有线程的默认异常处理器 */ Thread.setDefaultUncaughtExceptionHandler(new MyThreadException()); } @Override public void run() { /** * 设置当前线程的异常处理为自定义的处理方式 */ Thread.currentThread().setUncaughtExceptionHandler(new MyThreadException()); throw new RuntimeException("我是自定义异常"); }}<div class="se-preview-section-delimiter"></div>
使用线程工场
public class MyFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setUncaughtExceptionHandler(new MyThreadException()); return t; }}<div class="se-preview-section-delimiter"></div>
测试
public class ThreadFactoryExceptionTest { public static void main(String[] args) { ExecutorService service = new ThreadPoolExecutor(10, 12, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new MyFactory()); service.execute(() -> {throw new RuntimeException("SSSXXX");}); service.shutdown(); }}<div class="se-preview-section-delimiter"></div>
通过Future的get方法捕获异常
使用线程池提交一个能获取到返回信息的方法,也就是ExecutorService.submit(Callable)
在submit之后可以获得一个线程执行结果的Future对象,而如果子线程中发生了异常,通过future.get()获取返回值时,可以捕获到
public class ChildThread implements Callable<String> { @Override public String call() throws Exception { Ex(); return ""; } private void Ex() { throw new RuntimeException("自定义异常"); }}<div class="se-preview-section-delimiter"></div>
public class CallableTest { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); Future<String> submit = executor.submit(new ChildThread()); try { submit.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { if (executor != null) { executor.shutdown(); } } }}
- 7、多线的异常处理
- 异常,多异常,异常处理
- C++ 异常处理:类的异常处理--异常处理类
- C++ 异常处理:类的异常处理
- Windows Phone 7 异常的人性化处理
- 多个Catch的异常处理
- C#的异常处理
- 异常处理的常见问题
- Java异常的处理
- 异常处理的技巧
- java的异常处理
- 异常的处理
- 统一的处理异常
- ruby的异常处理
- InvocationHandler 的异常处理
- java的异常处理
- ARM的异常处理
- JNI异常的处理
- 原木加工
- linux-war文件操作
- 6、ThreadLocal线程变量
- 用邻接链表存储图并且实现拓扑排序
- centos 搭建svn
- 7、多线的异常处理
- 【MoveIt!和Gazebo】Failed to validate trajectory: couldn't receive full current joint state
- 8、线程的中断机制
- python判断字符串是否包含子字符串的方法
- 使用Nexus搭建Maven私服托管Android aar或jar包
- 卡在一个bug时不要忽视任何一个小问题
- SAP2000V20中文免费版下载附安装教程
- 函数
- Linux+nginx+mysql+php实战nexusPHP