You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何返回已完成线程的结果列表?ThreadUnion实现问题排查

线程监控程序results()方法未收集正常线程结果问题
  • 现有线程分解程序,除results()方法外其余测试均通过,目前仅能收集抛出异常的线程结果,无法统计正常完成的线程。
  • 测试失败报错:

org.opentest4j.AssertionFailedError:
Expected :7
Actual :4

核心方法要求

  1. Thread newThread(Runnable runnable):创建并注册线程,命名规则为[name]-worker-n,需监控线程执行全过程
  2. 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;
}

关键修改点

  1. 对传入的Runnable进行包装,在try块执行原始任务,catch捕获所有异常,finally块中统一记录结束时间并添加结果到列表
  2. 保留UncaughtExceptionHandler作为兜底,处理Error等未被catch捕获的严重异常
  3. 确保FinishedThreadResult构造方法支持接收线程名、结束时间戳、异常三个参数(需根据实际定义调整)

这样修改后,正常完成的线程和异常线程的结果都会被收集,results()返回的数量就能匹配预期值。

内容的提问来源于stack exchange,提问作者Kere

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 08:07:48