3、Java多线程-处理子线程异常

处理子线程异常(重要)、
参考:https://www.cnblogs.com/jpfss/p/10272066.html
1、Java子线程中的异常处理
  父线程中启动子线程,直接在父线程启动子线程的地方try...catch,是捕获不到子线程的异常的
  原因:Runnable接口的run方法的完整签名,因为没有标识throws语句,所以方法是不会抛出checked异常的。至于RuntimeException这样的 unchecked异常,由于新线程由JVM进行调度执行,如果发生了异常,也不会通知到父线程。
2、处理子线程的异常
  子线程中处理:
    a.子线程中try...catch
    b.为子线程设置“未捕获异常处理器”UncaughtExceptionHandler
    既然a方法已经可以捕获异常,为什么还要有b存在,我的理解是a需要指定可能发生异常的代码,而b不需要指定,只要发生异常,对应的异常处理器自动处理。
  父线程中处理:
    c.通过Future的get方法捕获异常(推荐)

3、示例代码

  1 import java.util.ArrayList;
  2 import java.util.List;
  3 import java.util.concurrent.Callable;
  4 import java.util.concurrent.ExecutionException;
  5 import java.util.concurrent.ExecutorService;
  6 import java.util.concurrent.Executors;
  7 import java.util.concurrent.Future;
  8
  9 public class TestExceptionThred {
 10
 11     /**
 12      * @param args
 13      */
 14     public static void main(String[] args) {
 15         ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
 16         List<Future<String>> fetrueResult = new ArrayList<>();
 17         System.out.println("start");
 18
 19         try {
 20             System.out.println("ssssssss");
 21 //            newFixedThreadPool.execute(new ChildThread01());
 22 //            newFixedThreadPool.execute(new ChildThread01());
 23 //            newFixedThreadPool.execute(new ChildThread01());
 24
 25 //            newFixedThreadPool.execute(new ChildThread0101());
 26 //            newFixedThreadPool.execute(new ChildThread0101());
 27
 28 //            newFixedThreadPool.execute(new ChildThread02());
 29 //            newFixedThreadPool.execute(new ChildThread02());
 30
 31 //            newFixedThreadPool.execute(new ChildThread0202());
 32 //            newFixedThreadPool.execute(new ChildThread0202());
 33
 34             Future<String> result01 = newFixedThreadPool.submit(new ChildThread03());
 35             fetrueResult.add(result01);
 36             Future<String> result02 = newFixedThreadPool.submit(new ChildThread03());
 37             fetrueResult.add(result02);
 38             for (Future<String> result : fetrueResult) {
 39                 result.get();
 40             }
 41             System.out.println("eeeeeeeee");
 42         } catch (InterruptedException | ExecutionException e) {
 43             System.out.println("InterruptedException or ExecutionException has been handled");
 44         } catch (Exception e) {
 45             System.out.println("exception has been handled");
 46         } finally {
 47             System.out.println("finally");
 48             if (null != newFixedThreadPool) {
 49                 newFixedThreadPool.shutdown();
 50             }
 51         }
 52         System.out.println("end");
 53     }
 54
 55 }
 56
 57 /**
 58  * 子线程中发生异常,未处理直接抛出,这种情况下,子线程直接退出,且不会记录任何日志
 59  */
 60 class ChildThread01 implements Runnable {
 61
 62     /*
 63      * @see java.lang.Runnable#run()
 64      */
 65     @Override
 66     public void run() {
 67         System.out.println("ChildThread before exception");
 68         exceptionMethod();
 69         System.out.println("ChildThread before exception");
 70     }
 71
 72     private void exceptionMethod() {
 73         throw new RuntimeException("ChildThread01 exception");
 74     }
 75 }
 76
 77 /**
 78  * 解决方案1:在子线程中try...catch捕获异常
 79  * 子线程中发生异常,并在子线程中处理
 80  */
 81 /**
 82  * 为线程设置异常处理器。具体做法可以是以下几种:
 83  * (1)Thread.setUncaughtExceptionHandler设置当前线程的异常处理器;
 84  * (2)Thread.setDefaultUncaughtExceptionHandler为整个程序设置默认的异常处理器;
 85  * 如果当前线程有异常处理器(默认没有),则优先使用该UncaughtExceptionHandler类;
 86  * 否则,如果当前线程所属的线程组有异常处理器,则使用线程组的UncaughtExceptionHandler;
 87  * 否则,使用全局默认的DefaultUncaughtExceptionHandler;如果都没有的话,子线程就会退出。
 88  * 注意:子线程中发生了异常,如果没有任何类来接手处理的话,是会直接退出的,而不会记录任何日志。
 89  * 所以,如果什么都不做的话,是会出现子线程任务既没执行成功,也没有任何日志提示的“诡异”现象的。
 90  */
 91 class ChildThread0101 implements Runnable {
 92
 93     /*
 94      * @see java.lang.Runnable#run()
 95      */
 96     @Override
 97     public void run() {
 98         //可能发生异常的地方,用try...catch处理
 99         try {
100             System.out.println("ChildThread0101 before exception");
101             exceptionMethod();
102             System.out.println("ChildThread0101 before exception");
103         } catch (Exception e) {
104             System.out.println("exception has been handled in ChildThread0101");
105         }
106     }
107
108     private void exceptionMethod() {
109         throw new RuntimeException("ChildThread0101 exception");
110     }
111 }
112
113 /**
114  * 解决方案2:为子线程设置“未捕获异常处理器”UncaughtExceptionHandler
115  * 子线程中发生异常,并在子线程中处理
116  */
117 class ChildThread02 implements Runnable {
118     private static ChildThreadExceptionHandler exceptionHandler;
119
120     static {
121         exceptionHandler = new ChildThreadExceptionHandler();
122     }
123
124     @Override
125     public void run() {
126         //下面代码可能会发生异常,但是不需要用try...catch显示的包裹代码处理,
127         //定义的异常处理器会自动捕获异常,并在子线程中处理
128
129         //设置当前线程的异常处理器
130         Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler);
131         System.out.println("ChildThread02 do something 1");
132         exceptionMethod();
133         System.out.println("ChildThread02 do something 2");
134     }
135
136     private void exceptionMethod() {
137         throw new RuntimeException("ChildThread02 exception");
138     }
139
140     //为线程设置“未捕获异常处理器”UncaughtExceptionHandler
141     public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler {
142         public void uncaughtException(Thread t, Throwable e) {
143             System.out.println(String.format("handle exception in ChildThread02. %s", e));
144         }
145     }
146 }
147
148 /**
149  * 解决方案2
150  * 子线程中发生异常,并在子线程中处理
151  */
152 class ChildThread0202 implements Runnable {
153     private static ChildThreadExceptionHandler exceptionHandler;
154
155     static {
156         exceptionHandler = new ChildThreadExceptionHandler();
157         //设置所有线程的默认异常处理器
158         Thread.setDefaultUncaughtExceptionHandler(exceptionHandler);
159     }
160
161     public void run() {
162         System.out.println("ChildThread0202 do something 1");
163         exceptionMethod();
164         System.out.println("ChildThread0202 do something 2");
165     }
166
167     private void exceptionMethod() {
168         throw new RuntimeException("ChildThread0202 exception");
169     }
170
171     public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler {
172         public void uncaughtException(Thread t, Throwable e) {
173             System.out.println(String.format("handle exception in ChildThread0202. %s", e));
174         }
175     }
176 }
177
178 /**
179  * 解决方案3:通过Future的get方法捕获异常(推荐)
180  */
181 /**
182  * 使用线程池提交一个能获取到返回信息的方法,也就是ExecutorService.submit(Callable)
183  * 在submit之后可以获得一个线程执行结果的Future对象,而如果子线程中发生了异常,
184  * 通过future.get()获取返回值时,可以捕获到ExecutionException异常,从而知道子线程中发生了异常
185  *
186  * 注意,如果不调用future.get(),则不会捕获到异常;如果子线程发生异常,直接退出,无任何记录
187  * 如果启动了多个子线程,捕获到任何一个子线程的异常,父线程执行finally语句或执行后续代码
188  */
189 class ChildThread03 implements Callable<String> {
190     public String call() throws Exception {
191         System.out.println("ChildThread03 do something 1");
192         exceptionMethod();
193         System.out.println("ChildThread03 do something 2");
194         return "ChildThread03 test result";
195     }
196
197     private void exceptionMethod() {
198         throw new RuntimeException("ChildThread03 exception");
199     }
200 }

原文地址:https://www.cnblogs.com/6xiong/p/12005608.html

时间: 2024-10-10 15:00:20

3、Java多线程-处理子线程异常的相关文章

Java多线程之后台线程不执行finally

后台线程不执行finally package wzh.daemon; import java.util.concurrent.TimeUnit; class ADaemon implements Runnable { @Override public void run() { try { System.out.println("Starting ADaemon"); TimeUnit.SECONDS.sleep(1); } catch (Exception e) { System.ou

Java多线程之后台线程

将线程设置成后台线程Daemons 主线程结果后,后台线程将自动结果. package wzh.test; import java.util.concurrent.TimeUnit; class SimpleDaemons implements Runnable{ @Override public void run() { try { while (true) { TimeUnit.MILLISECONDS.sleep(100); System.out.println(Thread.curren

Java多线程总结之线程安全队列Queue

在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列.Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列. 注:什么叫线程安全?这个首先要明确.线程安全的类 ,指的是类内共享的全局变量的访问必须保证是不受多线程形式影响的.如果由于多线程的访问(比如修改.遍历.查看)而使这些变量结构被破坏

Java多线程-新特性-线程池

Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序,线程部分的新增内容显得尤为重要. 有关Java5线程新特征的内容全部在java.util.concurrent下面,里面包含数目众多的接口和类,熟悉这部分API特征是一项艰难的学习过程.目前有关这方面的资料和书籍都少之又少,大部分介绍线程方面书籍还停留在java5之前的知识层面上. 在Java5之

Java多线程系列--“JUC线程池”01之 线程池架构

概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构图线程池示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509903.html 线程池架构图 线程池的架构图如下: 1. Executor 它是"执行者"接口,它是来执行任务的.准确的说,Executor提供了execute()接口来执行

关于java多线程中守护线程的理解

在java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程.下面的方法就是用来设置守护线程的. 1 Thread daemonTread = new Thread(); 2 3 // 设定 daemonThread 为 守护线程,default false(非守护线程) 4 daemonThread.setDaemon(true); 5 6 // 验证当前线程是否为守护线程,返回 tr

java多线程二之线程同步的三种方法

java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Semaphore. 线程同步问题引入: 创建一个银行账户Account类,在创建并启动100个线程往同一个Account类实例里面添加一块钱.在没有使用上面三种方法的情况下: 代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

Java多线程理解(线程安全)

我们在使用Java多线程时,一定需要考虑到共享,线程安全的相关内容.以下通过几个例子帮助大家来理解多线程时如何运行的,后续通过一篇文章详述解决办法:synchronized. 场景1: 第一次运行结果: [当前线程]----------one=====实例变量的值----x=1 [当前线程]----------two=====实例变量的值----x=2 [当前线程]----------two=====实例变量的值----x=3 [当前线程]----------two=====实例变量的值----

winform 利用 多线程 处理窗体假死,利用 Invoke BeginInvoke 处理子线程调用 UI 控件报错的问题

因为工作需要自己写了一个简单的工具软件,数据库查询每日OA未发送成功流程的日志记录以及批量重处理操作. 开始使用的是单线程,后台查询数据库的时候窗体假死,使用多线程很简单就能解决. private void btnQuey_Click(object sender, EventArgs e) { this.button2.Enabled = false; Thread connectionThread = new Thread(new ThreadStart(connectDB)); connec