Java工程师知识树

Java基础-线程-线程的异常处理

2021-02-01  本文已影响0人  HughJin

Java工程师知识树 / Java基础


线程的异常处理

setDefaultUncaughtExceptionHandler():设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。Thread.setDefaultUncaughtExceptionHandler(new ThreadUncaughtExceptionHandler())

线程异常处理实例
package com.thread.study;

import org.slf4j.Logger;

import static org.slf4j.LoggerFactory.getLogger;

public class ThreadException {
    /** 日志 */
    private static final Logger LOGGER = getLogger(ThreadException.class);

    public static void main(String[] args) {
        //异常不处理
        new Thread(() -> {
            int i = 1/0;
        }, "张三").start();

        //在线程内异常处理
        new Thread(() -> {
            try {
                int i = 1/0;
            } catch (Exception e) {
                LOGGER.error("线程发生了异常,线程内处理", e);
            }
        }, "李四").start();

        // 在线程外处理异常
        try {
            new Thread(() -> {
                int i = 1/0;
            }, "王五").start();
        } catch (Exception e) {
            LOGGER.error("线程发生了异常,线程外处理", e);
        }

        // 自定义线程异常处理异常
        Thread thread = new Thread(() -> {
            int i = 1/0;
        },"赵六");
        thread.setUncaughtExceptionHandler(new ThreadUncaughtExceptionHandler());
        thread.start();
    }

}


// 自定义线程异常
class ThreadUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

    /** 日志 */
    private static final Logger LOGGER = getLogger(ThreadUncaughtExceptionHandler.class);

    /**
     * Thread t  发生异常的线程
     * Throwable e  发生的异常
     */
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        LOGGER.error("线程发生了异常,自定义处理。{}", t, e);
    }
}

打印结果
Exception in thread "张三" java.lang.ArithmeticException: / by zero
    at com.thread.study.ThreadException.lambda$main$0(ThreadException.java:14)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "王五" java.lang.ArithmeticException: / by zero
    at com.thread.study.ThreadException.lambda$main$2(ThreadException.java:29)
    at java.lang.Thread.run(Thread.java:745)
主线程执行完了
10:32:02.518 [李四] ERROR com.thread.study.ThreadException - 线程发生了异常,线程内处理
java.lang.ArithmeticException: / by zero
    at com.thread.study.ThreadException.lambda$main$1(ThreadException.java:20)
    at java.lang.Thread.run(Thread.java:745)
10:32:02.518 [赵六] ERROR com.thread.study.ThreadUncaughtExceptionHandler - 线程发生了异常,自定义处理。Thread[赵六,5,main]
java.lang.ArithmeticException: / by zero
    at com.thread.study.ThreadException.lambda$main$3(ThreadException.java:37)
    at java.lang.Thread.run(Thread.java:745)
线程异常处理总结:
  1. 线程中如果发生异常,不处理与在线程外处理效果是一样的。
  2. 线程中如果发生异常,在线程中处理可以捕捉到异常,线程的异常不影响其他线程的执行。
  3. 线程中如果发生异常,使用线程内的try...catch和自定义异常都是可以处理的,并可以获取线程内的异常信息。
  4. 线程内的try...catch和自定义异常处理异常的区别在于,线程内的try...catch只能针对一个线程,自定义异常可以针对一组线程。
线程通过Future的get方法捕获异常
package com.thread.study;

import org.slf4j.Logger;

import java.util.concurrent.*;

import static org.slf4j.LoggerFactory.getLogger;

public class ThException {

    /** 日志 */
    private static final Logger LOGGER = getLogger(ThreadException.class);

    public static void main(String[] args) {

        // 线程通过Future的get方法捕获异常
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<Object> future = executorService.submit(new Callable() {
            @Override
            public String call() throws Exception {
                int i = 1 / 0;
                return "线程通过Future创建线程";
            }
        });
        try {
            String reStr = (String) future.get();
            System.out.println(reStr);
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("线程发生了异常,线程通过Future的get方法捕获异常", e);
        }
        executorService.shutdown();

        System.out.println("主线程执行完了");
    }
}
// 打印结果
/*
11:10:41.841 [main] ERROR com.thread.study.ThreadException - 线程发生了异常,线程通过Future的get方法捕获异常
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at com.thread.study.ThException.main(ThException.java:26)
Caused by: java.lang.ArithmeticException: / by zero
    at com.thread.study.ThException$1.call(ThException.java:21)
    at com.thread.study.ThException$1.call(ThException.java:18)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
主线程执行完了
*/
通过Future的get方法处理总结:

submit之后可以获得一个线程执行结果的Future对象,而如果子线程中发生了异常,通过future.get()获取返回值时,可以捕获到ExecutionException异常,从而知道子线程中发生的异常信息。

上一篇 下一篇

猜你喜欢

热点阅读