如何返回已完成线程的结果列表?ThreadUnion实现问题排查
线程监控程序results()方法未收集正常线程结果问题
- 现有线程分解程序,除
results()方法外其余测试均通过,目前仅能收集抛出异常的线程结果,无法统计正常完成的线程。 - 测试失败报错:
org.opentest4j.AssertionFailedError:
Expected :7
Actual :4
核心方法要求
Thread newThread(Runnable runnable):创建并注册线程,命名规则为[name]-worker-n,需监控线程执行全过程List results():返回已完成线程的结果列表,每条结果需包含线程名、结束时间戳、异常(若有)
当前实现代码
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class ThreadUnionImpl implements ThreadUnion{ private final String name; private final AtomicInteger threadCount = new AtomicInteger(0); private final List<FinishedThreadResult> threadList = Collections.synchronizedList(new ArrayList<>()); private boolean shutdownRequested = false; public ThreadUnionImpl(String name) { this.name = name; } @Override public int totalSize() { return threadCount.get(); } @Override public int activeSize() { return (int)Thread.getAllStackTraces().keySet().stream() .filter(thread -> thread.getName().startsWith(name + "-worker-")) .count(); } @Override public void shutdown() { shutdownRequested = true; Thread.getAllStackTraces().keySet().stream() .filter(thread -> thread.getName().startsWith(name + "-worker-")) .forEach(Thread::interrupt); Thread.getAllStackTraces().keySet().stream() .filter(thread -> thread.getName().startsWith(name + "-worker-")) .forEach(Thread::interrupt); } @Override public boolean isShutdown() { return shutdownRequested; } @Override public void awaitTermination() { Thread.getAllStackTraces().keySet().stream() .filter(thread -> thread.getName().startsWith(name + "-worker-")) .forEach(thread -> { try { thread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } @Override public boolean isFinished() { return shutdownRequested && activeSize() == 0; } @Override public List<FinishedThreadResult> results() { return threadList; } @Override public Thread newThread(Runnable r) { if (shutdownRequested) throw new IllegalStateException(); String threadName = this.name + "-worker-" + threadCount.getAndIncrement(); Thread thread = new Thread(r, threadName); thread.setUncaughtExceptionHandler((t, e) -> { threadList.add(new FinishedThreadResult(t.getName(), e)); }); return thread; } }
问题分析与解决方案
当前代码仅通过UncaughtExceptionHandler捕获异常线程的结果,正常完成的线程不会触发该处理器,导致results()返回的结果数量不足。需要用catch-finally包装传入的Runnable,确保无论线程正常结束还是抛出异常,都能将结果写入列表。
修改newThread方法如下:
@Override public Thread newThread(Runnable r) { if (shutdownRequested) throw new IllegalStateException(); String threadName = this.name + "-worker-" + threadCount.getAndIncrement(); // 包装原始Runnable,添加监控逻辑 Runnable wrappedRunnable = () -> { Exception exception = null; long endTime = 0L; try { r.run(); // 执行原始任务 } catch (Exception e) { exception = e; // 捕获异常 } finally { endTime = System.currentTimeMillis(); // 记录结束时间戳 // 将结果加入列表,无论是否异常 threadList.add(new FinishedThreadResult(threadName, endTime, exception)); } }; Thread thread = new Thread(wrappedRunnable, threadName); // 保留UncaughtExceptionHandler作为兜底,防止未捕获的Error等 thread.setUncaughtExceptionHandler((t, e) -> { long endTime = System.currentTimeMillis(); threadList.add(new FinishedThreadResult(t.getName(), endTime, new RuntimeException(e))); }); return thread; }
关键修改点
- 对传入的
Runnable进行包装,在try块执行原始任务,catch捕获所有异常,finally块中统一记录结束时间并添加结果到列表 - 保留
UncaughtExceptionHandler作为兜底,处理Error等未被catch捕获的严重异常 - 确保
FinishedThreadResult构造方法支持接收线程名、结束时间戳、异常三个参数(需根据实际定义调整)
这样修改后,正常完成的线程和异常线程的结果都会被收集,results()返回的数量就能匹配预期值。
内容的提问来源于stack exchange,提问作者Kere
相关产品推荐
相关产品推荐

