多线程异常处理

多线程异常处理

子线程异常不能抛给主线程处理

public static void main(String[] args) {
	try {
		Thread thread = new Thread(() -> {
			int a = 1 / 0;
		});
		thread.start();
	} catch (Exception t) {
		System.out.println("thread exception is caughted here!");
	}
}

运行结果:
在这里插入图片描述
可以看出子线程的异常,主线程不能捕获。那么怎么处理多线程的异常呢?

方法一:设置线程的uncaughtExceptionHandler属性

因为多线程的抛出的未捕获异常会抛给JVM处理,JVM会调用线程的dispatchUncaughtException方法处理异常

    private void dispatchUncaughtException(Throwable e) {
        getUncaughtExceptionHandler().uncaughtException(this, e);
    }

    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }

如果线程设置了uncaughtExceptionHandler属性则通过其处理,如果没有设置则交给其所在线程组的uncaughtExceptionHandler处理

方法二:重写线程所在ThreadGroup的uncaughtExceptionHandler
    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }

如果当前线程组未重写uncaughtException方法,则会向上寻找它的父ThreadGroup,直到找到一个重写了uncaughtException方法的parent,否则就默认将异常打印出来。

小结:多线程处理异常机制:抛出未捕获异常 —》 JVM捕获 —》 交给当前线程的uncaughtExceptionHandler处理 —》交给其所在ThreadGroup处理—》交给Thread的DefaultUncaughtExceptionHandler处理—》打印在控制台

但是我们多线程通常是交给线程池处理,那么线程池里线程出现异常应该如何处理呢?

线程池的excute

首先通过前面的方法设置是不行的,因为excute实际会通过线程工程创建一个新的线程,去执行新线程的run方法,新线程的run方法里面包含了传过来线程的run方法

        public void run() {
            runWorker(this);
        }

多线程异常处理_第1张图片

protected void afterExecute(Runnable r, Throwable t) { }

excute的异常处理机制是:交给afterExecute()处理,默认afterExecute()是未实现的,所以excute的异常处理可以通过下面的方式实现

方法一: 自定义一个继承ThreadPoolExecutor的类,自己实现afterExecute方法,对异常进行统一处理

方法二: 可以在线程运行时通过Thread.currentThread().setUncaughtExceptionHandler设置当前线程的异常处理

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new Runnable() {
	@Override
	public void run() {
		Thread.currentThread().setUncaughtExceptionHandler((thread, exception) -> {
			System.out.println("deal exception");
		});
		int a = 1 / 0;
	}
});
线程池的submit

submit方法会创建一个FurtureTask对象,需要通过FutureTask对象调用get方法获取结果或者异常,因为运行的结果或者异常都会赋值变量outcome,需要通过get来获取。

参考文章: FutureTask 会 “吞掉“ 异常是怎么回事?需要注意些什么?.

你可能感兴趣的:(java学习)