✅如何实现主线程捕获子线程异常

典型回答

✅为什么不能在try-catch中捕获子线程的异常?

我们说过,没办法直接在主线程的try-catch中捕获子线程的异常。但是,有的时候子线程中会开启一些IO链接,网络资源等,那么,如何在抛出异常的时候进行处理呢?

有几个方案可以实现:

使用Future

如果想要在主线程能够捕获子线程的异常,可以考虑使用Callable和Future,它们允许主线程获取子线程的执行结果和异常。这样,主线程可以检查子线程是否抛出了异常,并在必要时处理它。以下是一个示例:

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Future<Integer> future = executor.submit(() -> {
            // 子线程抛出异常
            throw new RuntimeException("子线程异常");
        });

        try {
            Integer result = future.get();
            System.out.println("子线程结果: " + result);
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            System.out.println("捕获到子线程异常"));
        }

        executor.shutdown();
    }
}

以上代码输出结果:

捕获到子线程异常

即,子线程中抛出的异常,我们在主线程中的catch块中捕获到了。

UncaughtExceptionHandler

我们还可以使用UncaughtExceptionHandlerUncaughtExceptionHandler 是 Java 中的一个接口,用于处理未捕获异常,即那些没有被 try-catch 块捕获的异常。它允许定义自定义异常处理器,以便在线程出现未捕获异常时采取特定的操作。

有了它,我们就可以为线程设置一个自定义的未捕获异常处理器,当线程抛出未捕获异常时,该处理器会被调用,我们可以在其中记录异常信息、执行清理操作等。

以下是一个代码示例:

public class HollisUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("线程 " + t.getName() + " 抛出未捕获异常:" + e.getMessage());
        // 在这里可以执行自定义的异常处理逻辑
    }
}

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            throw new RuntimeException("这是一个未捕获异常");
        });

        // 设置自定义的未捕获异常处理器
        thread.setUncaughtExceptionHandler(new HollisUncaughtExceptionHandler());

        thread.start();
    }
}

在这个示例中,我们创建了一个自定义的 HollisUncaughtExceptionHandler ,并将其设置为线程的未捕获异常处理器。当线程执行时抛出未捕获异常,uncaughtException 方法会被调用,然后执行我们在其中实现的处理逻辑。

这样也就间接实现了在主线中捕获到子线程中抛出的异常。

CompletableFuture

Java 8引入了CompletableFuture,它允许你异步执行任务并处理异常。你可以使用CompletableFuture.supplyAsync()来执行任务,并使用handle()方法捕获异常。

✅CompletableFuture的底层是如何实现的?

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    // 子线程抛出异常
    throw new RuntimeException("子线程异常");
});

future.handle((result, exception) -> {
    if (exception != null) {
        System.out.println("捕获到子线程异常: " + exception.getMessage());
    } else {
        System.out.println("子线程结果: " + result);
    }
    return null;
});

原文: https://www.yuque.com/hollis666/xkm7k3/iao166g9qgzld9e3