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

多线程、并发与Thread.sleep()未按预期工作问题排查

ReentrantLock测试仅单个线程获取锁的问题排查与解决

问题场景

实现了lockAndWait方法,逻辑是获取ReentrantLock锁后,持有锁休眠1秒再释放。测试时启动10个线程调用该方法,但日志里只看到一个线程成功获取锁;移除Thread.sleep(1000)后,多个线程能正常获取锁。最终通过修改测试代码,用Thread.join等待所有线程执行,问题解决。

原方法代码

private final Lock lock = new ReentrantLock();

public void lockAndWait() {
    logger.info("I {} am here", Thread.currentThread().getName());
    lock.lock();
    try {
        logger.info("I {} got the lock", Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    } finally {
        lock.unlock();
    }
}

原测试代码(存在问题)

@Test
public void lockTest() {
    for (int i = 0; i < 10; i++) {
        new Thread(() -> lockAndWait()).start();
    }
}

问题原因

JUnit的测试方法运行在主线程中,主线程执行完毕后,整个测试进程会直接终止,不会主动等待子线程完成:

  • 原测试里,主线程循环启动10个线程后就结束了。第一个线程获取锁后休眠1秒的过程中,主线程已经终止,剩余9个线程还在等待锁或刚启动,根本没机会执行,所以日志只显示第一个线程的锁获取记录。
  • 移除Thread.sleep(1000)后,线程执行速度极快,主线程结束前可能有多个线程完成了加锁、执行、释放的流程,看起来符合预期,但这只是巧合,测试逻辑本身依然存在漏洞。

解决方法:用Thread.join等待所有子线程执行完毕

修改测试代码,保存所有启动的线程实例,遍历调用Thread.join(),让主线程等待每个子线程执行完成后再结束:

@Test
public void policyUsageTest() throws InterruptedException {
    List<Thread> threads = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        Thread thread = new Thread(() -> lockAndWait());
        thread.start();
        threads.add(thread);
    }
    // 等待所有线程执行完毕
    for (Thread thread : threads) {
        thread.join();
    }
}

修改后,主线程会一直等待所有10个线程完成加锁、休眠、释放锁的流程后才结束,日志会显示所有线程依次获取锁的记录,符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:03:22