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

多线程向ConcurrentHashMap存值遇类型转换错误及返回null问题

问题分析与解决方案

核心问题1:线程池任务未完成就返回结果

你调用executor.shutdown()后没有等待所有线程执行完毕,主线程会直接继续执行后续逻辑,此时调用getCrackedPasswords()时,Worker线程还在处理任务,自然返回空集合。而直接调用run()是在主线程同步执行,所有任务完成后才会返回,所以能拿到正确结果。

核心问题2:内部类类型转换错误

你的Worker是非静态内部类,默认持有外部Engine类的实例引用。错误提示里的强制转换问题,是代码中某处误将Engine的this引用强行转为Worker类型导致的(你提供的代码片段未体现,但结合错误信息可推断)。非静态内部类的实例依赖外部类实例,这种隐式引用很容易引发这类转换错误。

修复步骤

1. 等待线程池任务执行完成

修改runProcess()方法,在shutdown()后调用awaitTermination()等待所有线程结束:

public void runProcess() throws InterruptedException {
    ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
    for(int i=1; i<=NUM_THREADS; i++) {
        long workload = numCombs/NUM_THREADS;
        // 处理最后一个线程的边界,避免numCombs无法被NUM_THREADS整除的情况
        long end = (i == NUM_THREADS) ? numCombs : workload * i;
        Worker worker = new Worker(workload * (i-1), end);
        executor.execute(worker);
    }
    executor.shutdown();
    // 等待所有任务完成,超时时间可根据实际场景调整
    executor.awaitTermination(1, TimeUnit.HOURS);
}

2. 将Worker改为静态内部类

把Worker改成静态内部类,避免持有外部Engine的隐式引用,同时从根源解决类型转换问题:

static class Worker implements Runnable {
    private final MD4 md4 = new MD4();
    private final long iterationStart;
    private final long iterationEnd;
    private final ConcurrentHashMap<String, String> crackedPasswords;
    private final byte[][] hashBytes;

    // 静态内部类需要显式传入所需的外部类成员
    public Worker(long inStart, long inEnd, ConcurrentHashMap<String, String> crackedPasswords, byte[][] hashBytes) {
        this.iterationStart = inStart;
        this.iterationEnd = inEnd;
        this.crackedPasswords = crackedPasswords;
        this.hashBytes = hashBytes;
    }

    @Override
    public void run() {
        for(long iteration=iterationStart; iteration<iterationEnd; iteration++) {
            // 注意:currentPlain需与iteration关联,比如根据iteration生成对应明文,而非固定值
            checkHash(String.valueOf(iteration));
        }
    }

    private void checkHash(String plainText) {
        for(byte[] hashByte : hashBytes) {
            if (Arrays.equals(hashByte, md4.runDigest(plainText))){
                StringBuilder hex = new StringBuilder(hashByte.length*2);
                for(byte b: hashByte)
                    hex.append(String.format("%02x", b));

                crackedPasswords.putIfAbsent(hex.toString(), plainText);
            }
        }
    }
}

创建Worker时传入所需参数:

Worker worker = new Worker(workload * (i-1), end, crackedPasswords, hashBytes);

3. 修复未定义变量与逻辑错误

你提供的代码存在几个未定义变量,需补充完善:

  • 调整Engine构造方法,接收numThreads、numCombs、hashBytes参数:
private final int NUM_THREADS;
private final long numCombs;
private final byte[][] hashBytes;

public Engine(int numThreads, long numCombs, byte[][] hashBytes) {
    this.NUM_THREADS = numThreads;
    this.numCombs = numCombs;
    this.hashBytes = hashBytes;
}
  • currentPlain需与iteration绑定,否则所有线程处理的都是同一个值,导致逻辑错误。

额外优化建议

  • 使用Executors.newFixedThreadPool时,线程数建议不超过CPU核心数的2倍,避免线程过多引发上下文切换开销。
  • 可用CountDownLatch替代awaitTermination,更灵活控制等待逻辑:
public void runProcess() throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(NUM_THREADS);
    ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
    for(int i=1; i<=NUM_THREADS; i++) {
        long workload = numCombs/NUM_THREADS;
        long end = (i == NUM_THREADS) ? numCombs : workload * i;
        Worker worker = new Worker(workload * (i-1), end, crackedPasswords, hashBytes, latch);
        executor.execute(worker);
    }
    executor.shutdown();
    latch.await(); // 等待所有线程完成
}

对应的Worker类需添加CountDownLatch参数,并在run方法最后调用latch.countDown():

static class Worker implements Runnable {
    private final CountDownLatch latch;
    // 其他成员...

    public Worker(..., CountDownLatch latch) {
        // 初始化逻辑...
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            // 循环处理逻辑
        } finally {
            latch.countDown();
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:24:54