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

Java并发测试中匿名Runnable调用Set.add()不生效是什么原因?

并发ID生成器唯一性测试集合为空问题解决方案

问题根因

你的代码仅实现了让20个工作线程同时触发ID生成的起跑同步逻辑,未做主线程等待所有工作线程完成ID写入集合的结束同步:提交完任务后主线程会立即执行断言,此时工作线程大概率还未执行到uniqueSet.add(id)逻辑,因此集合大小为0。

解决方案

方案1:新增结束同步锁存器(推荐,保留原有线程同时起跑的压测逻辑)

你当前的CountDownLatch仅用于让所有线程同时开始执行,新增一个结束用的锁存器等待所有线程完成写入即可:

@Test
void should_generate_unique_id_concurrently() throws InterruptedException {
    Set<Long> uniqueSet = ConcurrentHashMap.newKeySet();
    final int numberOfThreads = 20;
    ExecutorService service = Executors.newFixedThreadPool(numberOfThreads);
    // 原有起跑同步锁存器:让所有线程同时开始生成ID
    CountDownLatch startLatch = new CountDownLatch(numberOfThreads);
    // 新增结束同步锁存器:等待所有线程完成ID写入
    CountDownLatch endLatch = new CountDownLatch(numberOfThreads);
    for (int i = 0; i < numberOfThreads; i++) {
        service.submit(() -> {
            try {
                startLatch.countDown();
                startLatch.await();
                long id = idGenerator.nextId();
                uniqueSet.add(id);
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            } finally {
                // 无论是否异常都计数,避免主线程永久阻塞
                endLatch.countDown();
            }
        });
    }
    // 主线程等待所有工作线程完成写入后再执行断言
    endLatch.await();
    service.shutdown();
    assertEquals(numberOfThreads, uniqueSet.size());
}

方案2:直接等待线程池所有任务执行完成

如果不需要严格控制所有线程同时起跑,可以直接关闭线程池后等待任务结束:

@Test
void should_generate_unique_id_concurrently() throws InterruptedException {
    Set<Long> uniqueSet = ConcurrentHashMap.newKeySet();
    final int numberOfThreads = 20;
    ExecutorService service = Executors.newFixedThreadPool(numberOfThreads);
    for (int i = 0; i < numberOfThreads; i++) {
        service.submit(() -> {
            long id = idGenerator.nextId();
            uniqueSet.add(id);
        });
    }
    service.shutdown();
    // 等待最长1分钟所有任务执行完成
    service.awaitTermination(1, TimeUnit.MINUTES);
    assertEquals(numberOfThreads, uniqueSet.size());
}

补充注意事项

  • 捕获InterruptedException后建议手动恢复线程中断状态,避免吞掉中断信号
  • 如果修改后断言还是失败,说明idGenerator本身存在重复生成ID的问题,需要进一步排查ID生成逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:06:03