Java多线程异常必须在线程内部捕获,因异常不跨线程传播;常用方式包括:1.在run()中用try-catch处理;2.设置UncaughtExceptionHandler兜底捕获未处理的运行时异常;3.使用Callable+Future,通过Future.get()将子线程异常以ExecutionException形式抛回主线程处理。

Java里多线程下的try-catch不是“把主线程的catch套住子线程”就能生效的——每个线程有自己独立的执行栈,异常不会跨线程传播。想让异常被真正捕获和处理,必须在发生异常的线程内部做安排。
在线程run()方法里加try-catch
这是最直接、最常用的做法。Runnable的run()方法不声明抛出任何checked exception,所以所有异常(包括IOException这类受检异常)都必须在内部处理。
- 把可能出错的逻辑(比如网络请求、文件读写、除零运算)放进try块
- 用具体异常类型写catch,比如ArithmeticException、NullPointerException、IOException,避免只写Exception兜底
- 在catch里记录日志、重试、通知主线程(如通过共享变量或CountDownLatch),或做必要清理
- 不要留空catch——捕获了却不处理,等于掩盖问题
为线程设置UncaughtExceptionHandler
当线程抛出未被捕获的运行时异常(如NullPointerException),JVM会调用该线程的UncaughtExceptionHandler。这是兜底机制,适合统一监控和日志。
- 可通过Thread.setUncaughtExceptionHandler()为单个线程设置
- 也可用Thread.setDefaultUncaughtExceptionHandler()设全局默认处理器
- 处理器里建议至少打印堆栈、记录时间戳和线程名,便于排查
- 注意:它只捕获unchecked异常;checked异常若没在run()里处理,编译就过不去
用Callable+Future获取异常结果
如果需要主线程主动感知子线程的异常,并做响应(比如失败后降级、重试),推荐用Callable替代Runnable。
立即学习“Java免费学习笔记(深入)”;
- Callable.call()允许抛出异常,且能返回结果
- 提交后拿到Future对象,调用get()时,若子线程抛异常,会包装成ExecutionException抛出
- 主线程可捕获ExecutionException,再用getCause()拿到原始异常,分类处理
- 这种方式让异常“回归主线程上下文”,便于集中控制流程
finally在多线程中依然可靠但需注意资源归属
只要线程没被强制终止(如stop()已废弃,System.exit()会杀整个JVM),finally就一定会执行——这点在线程内完全成立。
- 适合释放本线程独占的资源:比如它自己打开的FileInputStream、Socket、数据库连接
- 若多个线程共用静态资源(如一个static FileWriter),finally里关流前得加锁,否则可能引发并发问题
- JDK 7+更推荐用try-with-resources,自动关闭AutoCloseable资源,语义更清晰、不易漏
- 别在finally里写return——会覆盖try/catch里的返回值,还容易让逻辑难理解


















