线程中处理异常是个头疼的问题,在异步的代码中,如何将异常捕获。

捕获异常后,将异常反馈给开发者,或最终用户。

一、将异常反馈给开发者,一般来说,在日志中打印异常日志即可;

二、将异常反馈给最终用户,一般来说,在页面上弹出提示框即可。

将异常打印到日志中(UncaughtExceptionHandler方式处理异常)

在线程当中遇到异常,需要捕捉并打印日志,我们可以考虑使用UncaughtExceptionHandler的回调。

以下是一个简单的测试例子。

有一个线程,方法体中会抛出异常

package com.nicchagil.study.thread.thinking.No15线程异常的捕捉;

public class ExceptionThread implements Runnable {

    @Override
public void run() {
throw new NullPointerException("故意抛出的异常。");
} }

自定义的异常处理器,这里所做的操作仅是在控制台打印异常,告诉开发者(并非用户哦)有这么个异常发生

package com.nicchagil.study.thread.thinking.No15线程异常的捕捉;

import java.lang.Thread.UncaughtExceptionHandler;

public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {

    @Override
public void uncaughtException(Thread t, Throwable throwable) {
System.out.println("Print exception @ MyUncaughtExceptionHandler -> " + throwable);
} }

为设置方便,通常可以有一个线程工厂(当然也可以直接设置,不通过工厂了),已帮忙批量以通用的参数设置产生线程。见调用类可见,有触发方法使用到此工厂,也有直接实例化线程的。

package com.nicchagil.study.thread.thinking.No15线程异常的捕捉;

import java.util.concurrent.ThreadFactory;

public class HandlerThreadFactory implements ThreadFactory {

    @Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
return t;
} }

触发类,这里介绍两种设置方式(一直接设置;一通过工厂设置),还有一种错误的设置方式,以供借镜。

package com.nicchagil.study.thread.thinking.No15线程异常的捕捉;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Call { public static void main(String[] args) {
/* Work */
callByWay1(); /* Work */
callByWay2(); /* Un-work */
callByWay3();
} /**
* 原始的调用方式,在Thread对象设置异常处理器
*/
public static void callByWay1() {
try {
Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
t.start();
} catch (Throwable t) {
System.out.println("Print exception @ Call.java -> " + t);
}
} /**
* 使用工厂设置异常处理器的调用方式
*/
public static void callByWay2() {
try {
ExecutorService es = Executors.newCachedThreadPool(new HandlerThreadFactory());
es.execute(new ExceptionThread());
} catch (Throwable t) {
System.out.println("Print exception @ Call.java -> " + t);
}
} /**
* 实例化Thread后,传入ExecutorService调用。(此方法不行,原因见代码内注释)
*/
public static void callByWay3() {
try {
Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); ExecutorService es = Executors.newCachedThreadPool();
/* 此方法不行,异常处理器虽在前面设置,但由于es.execute(t)的入参为Runnable,故异常处理器遗失 */
es.execute(t);
} catch (Throwable t) {
System.out.println("Print exception @ Call.java -> " + t);
}
} }

日志如下,可见:

  1. 如果正确设置了异常处理器,将会触发异常处理器。我们的异常处理器中书写的逻辑是打印日志,所以,日志打印出来了。
  2. 无论有无设置异常处理器,异常都不会被直接的catch块捕捉和打印
Print exception @ MyUncaughtExceptionHandler -> java.lang.NullPointerException: 故意抛出的异常。
Print exception @ MyUncaughtExceptionHandler -> java.lang.NullPointerException: 故意抛出的异常。
Exception in thread "pool-1-thread-1" java.lang.NullPointerException: 故意抛出的异常。
at com.nicchagil.study.thread.thinking.No15线程异常的捕捉.ExceptionThread.run(ExceptionThread.java:7)
at java.lang.Thread.run(Thread.java:619)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)

将异常提示给最终用户(捕获异常)

告诉最终用户有异常发生,则需要捕获线程执行过程中产生的异常,捕获异常后传递给页面进行提示。

执行线程,并捕获异常:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class MyThread implements Callable<String> { @Override
public String call() throws Exception {
if (1 == 1) {
throw new RuntimeException("模拟的一个异常");
} return "hello world";
} public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool(); try {
Future<String> f = es.submit(new MyThread());
System.out.println(f.get());
} catch (Throwable t) {
System.out.println("捕获异常 : " + t.getMessage());
}
} }

日志:

看到“捕获异常 : java.lang.RuntimeException: 模拟的一个异常”就知道异常被捕捉了,剩下的就看你如何传到JSP了,哈哈哈。

捕获异常 : java.lang.RuntimeException: 模拟的一个异常

Runnable的线程也是可以的:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class MyThread implements Runnable { @Override
public void run() {
System.out.println(Thread.currentThread().getName() + " run.");
throw new RuntimeException("模拟的一个异常");
} public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool(); try {
Future<?> f = es.submit(new MyThread());
System.out.println(f.get());
} catch (Throwable t) {
System.out.println("捕获异常 : " + t.getMessage());
}
} }

【Thread】多线程的异常处理?的更多相关文章

  1. 多线程的异常处理、线程取消、临时变量、lock

    异步多线程的异常,抓不到,因为是在子线程执行. #region 多线程的异常处理.线程取消.临时变量.lock { try { List<Task> list = new List< ...

  2. java 多线程 线程组ThreadGroup;多线程的异常处理。interrupt批量停止组内线程;线程组异常处理

    1,线程组定义: 线程组存在的意义,首要原因是安全.java默认创建的线程都是属于系统线程组,而同一个线程组的线程是可以相互修改对方的数据的.但如果在不同的线程组中,那么就不能"跨线程组&q ...

  3. PowerBuilder编程新思维2:嵌入(Thread多线程)

    PowerBuilder编程新思维2:嵌入(Thread多线程) 在PB中使用多线程,在网上有大量的文章介绍.不过深入研究并试着给出更易用的模型的,目前还只有"路人甲cw"的一篇& ...

  4. Ptypes一个开源轻量级的c++库,包括对一些I/O操作、网络通信、多线程和异常处理的封装

    C++开源项目入门级:Ptypes    Ptypes一个开源轻量级的c++库,包括对一些I/O操作.网络通信.多线程和异常处理的封装.虽然代码有限,包括的内容不少,麻雀虽小,五脏俱全.    提高: ...

  5. C++ std::thread 多线程中的异常处理

    环境: VS2019 包含头文件: #include <iostream>#include<thread>#include<exception> 线程函数采用try ...

  6. .NET进阶篇06-async异步、thread多线程1

    知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 异步多线程挺大一块内容,既想拆开慢慢学,又想一股脑全倒出.纠结再三,还是拆开吃透,也不至于篇幅过长,劝退许多人 本篇先做一个概述,列明一些基本概 ...

  7. .NET进阶篇06-async异步、thread多线程2

    知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 内容目录 一.线程Thread1.生命周期2.后台线程3.静态方法1.线程本地存储2.内存栅栏4.返回值二.线程池ThreadPool1.工作队 ...

  8. C# 多线程总结 异常处理 线程取消 锁(lock)

    那么什么时候能用多线程? 任务能并发的时候 多线程能干嘛?提升速度/优化用户体验 网站首页:A数据库 B接口 C分布式服务 D搜索引擎,适合多线程并发,都完成后才能返回给用户,需要等待WaitAll列 ...

  9. JUC学习笔记--Thread多线程基础

    实现多线程的两种方法 java 实现多线程通过两种方式1.继承Thread类 ,2.实现Runnable接口 class Newthead extends Thread{ public void ru ...

随机推荐

  1. CCF真题之最优灌溉

    201412-4 问题描述 雷雷承包了很多片麦田,为了灌溉这些麦田,雷雷在第一个麦田挖了一口很深的水井,所有的麦田都从这口井来引水灌溉. 为了灌溉,雷雷需要建立一些水渠,以连接水井和麦田,雷雷也可以利 ...

  2. 夺命雷公狗---DEDECMS----6快速入门之总结篇

    我们dedecms四大表分别是: dede_channeltype(模型表) dede_arctype(栏目表) dede_archives(文章主表) dede_addonXXXX(附加表) 使用d ...

  3. 夺命雷公狗jquery---4内容选择器

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  4. Vim篇

    Vim编辑器中的一些常用命令: 1:shift+* , 选取光标所在处的整个字符,并查找.(十分方便),快捷键gd 2:set nu , 显示各行行号,使得基于行的命令更方便. 3:shift+% , ...

  5. (第九周)视频发布及git统计报告

    项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 代码地址:HTTPS: https://git.coding.net/li_yuhuan/FoodChain. ...

  6. ASP.NET MVC(二)

    休息一下还是继续ASP.NET MVC 的基础知识. 这篇文件我想和大家一起熟悉下ASP.NET MVC项目的目录结构及dll. 1. ASP.NET MVC 项目的目录结构 App_Data:  存 ...

  7. Openstack的HA解决方案【替换原有的dashboard】

    0. 进入到/etc/haproxy/conf.d/目录下 mv 015-horizon.cfg 150-timaiaas.cfg 将原有的dashboard的ha配置文件做为自己的配置文件. 1. ...

  8. FastJson--阿里巴巴公司开源的速度最快的Json和对象转换工具(转)

    本文转自:http://blog.csdn.net/djun100/article/details/24237371 这是关于FastJson的一个使用Demo,在Java环境下验证的 class U ...

  9. linux设备驱动归纳总结(四):4.单处理器下的竞态和并发【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-67005.html linux设备驱动归纳总结(四):4.单处理器下的竞态和并发 xxxxxxxxxx ...

  10. Objective-C占位符

    %@ 对象 %d, %i 整数 %li 长整型 %u 无符号整形 %f 浮点/双字 %x, %X 二进制整数 %o 八进制整数 %zu size_t %p 指针 %e 浮点/ 双字 (科学计算) (d ...