1 目标:
由于线程池内部的线程发生异常后不会主动报告具体是哪个线程出现的异常,本文章旨在解决获取出现异常的线程号。
2 第一种实现方法-自定义线程工厂
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolTest {
// 自定义线程工厂
public static class NamedThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
public NamedThreadFactory(String namePrefix) {
this.namePrefix = namePrefix + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
t.setUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("线程[" + thread.getName() + "]抛出异常: " + throwable);
throwable.printStackTrace();
});
return t;
}
}
public static void main(String[] args) {
// 1. 创建使用自定义线程工厂的线程池
ExecutorService executor = Executors.newFixedThreadPool(3, new NamedThreadFactory("my-pool"));
System.out.println("开始提交任务...");
// 2. 提交正常任务
executor.submit(() -> {
System.out.println("正常任务执行 - 线程: " + Thread.currentThread().getName());
});
// 3. 提交会抛出异常的任务
executor.submit(() -> {
System.out.println("即将抛出异常的任务 - 线程: " + Thread.currentThread().getName());
// 模拟异常
throw new RuntimeException("模拟的业务异常");
});
// 4. 提交更多任务观察线程命名
for (int i = 0; i < 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("任务" + taskId + "执行 - 线程: " + Thread.currentThread().getName());
});
}
// 5. 关闭线程池
executor.shutdown();
System.out.println("所有任务已提交,线程池正在关闭...");
}
}
3 使用Future
package TestThread;
import java.util.*;
import java.util.concurrent.*;
public class FutureExceptionHandlingExample {
public static void main(String[] args) {
// 1. 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
System.out.println("开始提交任务...");
// 2. 提交多个任务,其中包含会抛出异常的任务
Future<?> future1 = executor.submit(() -> {
System.out.println("任务1开始执行 - 线程: " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟工作
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("任务1正常完成");
});
Future<?> future2 = executor.submit(() -> {
System.out.println("任务2开始执行 - 线程: " + Thread.currentThread().getName());
Thread.sleep(500); // 模拟工作
// 模拟业务异常
throw new RuntimeException("任务2的业务处理失败");
});
Future<?> future3 = executor.submit(() -> {
System.out.println("任务3开始执行 - 线程: " + Thread.currentThread().getName());
try {
Thread.sleep(800); // 模拟工作
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("任务3正常完成");
});
// 3. 收集所有Future(Java 8兼容方式)
List<Future<?>> futures = Arrays.asList(future1, future2, future3);
// 4. 检查每个Future的执行结果
for (int i = 0; i < futures.size(); i++) {
try {
futures.get(i).get(); // 获取执行结果,会抛出异常
System.out.println("任务" + (i+1) + "执行成功");
} catch (InterruptedException e) {
System.err.println("任务" + (i+1) + "被中断: " + e.getMessage());
Thread.currentThread().interrupt(); // 恢复中断状态
} catch (ExecutionException e) {
// 这里获取的是实际任务抛出的异常
Throwable cause = e.getCause();
System.err.println("任务" + (i+1) + "执行失败,原因: " + cause.getMessage());
// 可以根据不同的异常类型进行特定处理
if (cause instanceof RuntimeException) {
System.err.println("这是一个运行时异常,需要记录日志并通知相关人员");
}
// 打印完整堆栈
cause.printStackTrace();
}
}
// 5. 关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
System.out.println("所有任务处理完成");
}
}
4 内部获取异常并记录
package TestThread;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestRun {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(6);
executorService.execute(new Runnable() {
public void run() {
try{
System.out.println(Thread.currentThread().getName()+"is running");
throw new RuntimeException("Exception in task");
}catch (Exception e){
System.out.println("手动打印异常"+Thread.currentThread().getName()+":"+e);
e.printStackTrace();
}
}
});
}
}