一、概述

  为什么要单独讲多线程的异常捕捉呢?先看个例子:

  1. public class ThreadException implements Runnable{
  2. @Override
  3. public void run() {
  4. throw new RuntimeException();
  5. }
  6. //现象:控制台打印出异常信息,并运行一段时间后才停止
  7. public static void main(String[] args){
  8. //就算把线程的执行语句放到try-catch块中也无济于事
  9. try{
  10. ExecutorService exec = Executors.newCachedThreadPool();
  11. exec.execute(new ThreadException());
  12. }catch(RuntimeException e){
  13. System.out.println("Exception has been handled!");
  14. }
  15. }
  16. }

  在run中手动抛出了一个运行时异常,在main中启动线程,catch语句块中捕捉下异常,捕捉到打印一句话。运行结果如下图:

  发现异常被抛到了控制台,没有打印catch块中的语句。

  结论:多线程运行不能按照顺序执行过程中捕获异常的方式来处理异常,异常会被直接抛出到控制台(由于线程的本质,使得你不能捕获从线程中逃逸的异常。一旦异常逃逸出任务的run方法,它就会向外传播到控制台,除非你采用特殊的形式捕获这种异常。),这样会让你很头疼,无法捕捉到异常就无法处理异常而引发的问题。

  于是,我们一定会想如何在多线程中捕捉异常呢?

二、多线程中捕捉异常

  我们来按照下面的步骤完成这次实验:

  1.定义异常处理器

   要求,实现 Thread.UncaughtExceptionHandler的uncaughtException方法,如下:

  1. /*
  2. * 第一步:定义符合线程异常处理器规范的“异常处理器”
  3. * 实现Thread.UncaughtExceptionHandler规范
  4. */
  5. class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
  6. /*
  7. * Thread.UncaughtExceptionHandler.uncaughtException()会在线程因未捕获的异常而临近死亡时被调用
  8. */
  9. @Override
  10. public void uncaughtException(Thread t, Throwable e) {
  11. System.out.println("caught "+e);
  12. }
  13. }

  2.定义使用该异常处理器的线程工厂

  1. /*
  2. * 第二步:定义线程工厂
  3. * 线程工厂用来将任务附着给线程,并给该线程绑定一个异常处理器
  4. */
  5. class HanlderThreadFactory implements ThreadFactory{
  6. @Override
  7. public Thread newThread(Runnable r) {
  8. System.out.println(this+"creating new Thread");
  9. Thread t = new Thread(r);
  10. System.out.println("created "+t);
  11. t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());//设定线程工厂的异常处理器
  12. System.out.println("eh="+t.getUncaughtExceptionHandler());
  13. return t;
  14. }
  15. }

  3.定义一个任务,让其抛出一个异常

  1. /*
  2. * 第三步:我们的任务可能会抛出异常
  3. * 显示的抛出一个exception
  4. */
  5. class ExceptionThread implements Runnable{
  6. @Override
  7. public void run() {
  8. Thread t = Thread.currentThread();
  9. System.out.println("run() by "+t);
  10. System.out.println("eh = "+t.getUncaughtExceptionHandler());
  11. throw new RuntimeException();
  12. }
  13. }

  4.调用实验

  1. /*
  2. * 第四步:使用线程工厂创建线程池,并调用其execute方法
  3. */
  4. public class ThreadExceptionUncaughtExceptionHandler{
  5. public static void main(String[] args){
  6. ExecutorService exec = Executors.newCachedThreadPool(new HanlderThreadFactory());
  7. exec.execute(new ExceptionThread());
  8. }
  9. }

  运行结果如下图:

三、结论

  在java中要捕捉多线程产生的异常,需要自定义异常处理器,并设定到对应的线程工厂中(即第一步和第二步)。

四、拓展

  如果你知道将要在代码中处处使用相同的异常处理器,那么更简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获处理器。

这个处理器只有在不存在线程专有的未捕获异常处理器的情况下才会被调用。

  1. public static void main(String[] args){
  2. Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
  3. ExecutorService exec =Executors.newCachedThreadPool();
  4. exec.execute(new ExceptionThread());
  5. }

注:以上代码均来自《thinking in java》,内容均是自己总结,如有错误,欢迎大家批评指正

Java多线程——<七>多线程的异常捕捉的更多相关文章

  1. JAVA并发七(多线程环境中安全使用集合API)

    在集合API中,最初设计的Vector和Hashtable是多线程安全的.例如:对于Vector来说,用来添加和删除元素的方法是同步的.如果只有一个线程与Vector的实例交互,那么,要求获取和释放对 ...

  2. Java多线程——<八>多线程其他概念

    一.概述 到第八节,就把多线程基本的概念都说完了.把前面的所有文章加连接在此: Java多线程——<一>概述.定义任务 Java多线程——<二>将任务交给线程,线程声明及启动 ...

  3. 七. 多线程编程2.Java线程模型

    Java运行系统在很多方面依赖于线程,所有的类库设计都考虑到多线程.实际上,Java使用线程来使整个环境异步.这有利于通过防止CPU循环的浪费来减少无效部分. 为更好的理解多线程环境的优势可以将它与它 ...

  4. Java线程和多线程(四)——主线程中的异常

    作为Java的开发者,在运行程序的时候会碰到主线程抛异常的情况.如果开发者使用Java的IDE比如Eclipse或者Intellij IDEA的话,可能是不需要直接面对这个问提的,因为IDE会处理运行 ...

  5. Java中的 多线程编程

    Java 中的多线程编程 一.多线程的优缺点 多线程的优点: 1)资源利用率更好2)程序设计在某些情况下更简单3)程序响应更快 多线程的代价: 1)设计更复杂虽然有一些多线程应用程序比单线程的应用程序 ...

  6. 关于java基础、多线程、JavaWeb基础、数据库、SSM、Springboot技术汇总

    作者 : Stanley 罗昊 本人自行总结,纯手打,有疑问请在评论区留言 [转载请注明出处和署名,谢谢!] 一.java基础 1.多态有哪些体现形式? 重写.重载 2. Overriding的是什么 ...

  7. Java基础技术多线程与并发面试【笔记】

    Java基础技术多线程与并发 什么是线程死锁? ​死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,我们就可以称 ...

  8. Java学习笔记-多线程-创建线程的方式

    创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...

  9. Java线程与多线程教程

    本文由 ImportNew - liken 翻译自 Journaldev.   Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...

随机推荐

  1. 在ubuntu上使用wxWidgets成功开发一个图形界面程序

    编译wxWidgets 下载最新版的源码,wxWidgets-3.0.2.wxWidgets在liunx是通过wxGTK实现的.wxGTK和wxWidgets的源码打包在一起.wxGTK依赖GTK+, ...

  2. phpQuery采集微信公众号文章乱码

    终于找到解决方案了,这是一个值得庆祝的事情.... 原来是因为微信在源码中加入了防采集代码<!--headTrap<body></body><head>< ...

  3. ASP.NET中application对象

    ASP.NET中application对象的使用. Application对象的应用  1.使用Application对象保存信息  (1).使用Application对象保存信息  Applicat ...

  4. Win10下IIS配置图解、MVC项目发布图解、IIS添加网站图解

    Win10下IIS配置 .找到控制面板:[开始]菜单鼠标右击,打开[控制面板] .打开控制面板,点击[程序],点击[启用或关闭Windows功能] 下一步,点击[启用虎关闭Windows功能] . 开 ...

  5. jQuery 插件开发解析

    那么首先我们来简单的看一下最正统的 jQuery 插件定义方式: (function ($) { $.fn.插件名 = function (settings) { //默认参数 var default ...

  6. STM32F0xx_DAC输出电压配置详细过程

    前言 数模转换DAC的功能在现实应用中所占的分量,相对定时器TIM.串口USART等要小的多,这也是ST为什么内部集成DAC模块相对来说不是那么多的原因.但在有需要使用数模转换功能的项目中,自带的这个 ...

  7. 8.python中的数字

    python中数字对象的创建如下, a = 123 b = 1.23 c = 1+1j 可以直接输入数字,然后赋值给变量. 同样也可是使用类的方式: a = int(123) b = float(1. ...

  8. UIViewAnimationOptions swift 2

    UIView.animateWithDuration(0.5, delay: 0.5, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, ...

  9. 浅谈objective—C管理内存

    这段时间被导师催着论文,调试各种BUg,也是醉了,发现很大程度上,内存出错,栈溢出,各种悲剧.那么今天就和大家一起对OC的内存管理来个探微吧.Objective-C使用一个保留计数记录了我们所创建的所 ...

  10. MySQL 的数值数据类型

    MySQL 的数值数据类型可以大致划分为两个类别,一个是整数,另一个是浮点数或小数.许多不同的子类型对这些类别中的每一个都是可用的,每个子类型支持不同大小的数据,并且 MySQL 允许我们指定数值字段 ...