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

Java多线程同步锁场景下Thread.sleep(1)导致执行时间异常的原因排查

Java多线程同步锁场景下Thread.sleep(1)导致执行时间异常的原因排查

嘿,这个问题我之前也踩过一模一样的坑!核心原因不是你的锁用错了,也不是JVM版本的锅,而是Thread.sleep(1)的实际睡眠时间根本不是精确的1毫秒,再加上操作系统线程调度的额外开销,直接把总耗时给放大了。

我来给你拆解清楚:

1. Thread.sleep(1)的“小谎言”

你以为调用Thread.sleep(1)线程就会精确休眠1ms?其实完全不是!这个方法的语义是“让线程至少休眠指定的毫秒数”,但实际休眠时间取决于操作系统的时钟中断粒度:

  • 比如Windows系统默认的时钟粒度是15.6ms左右(老版本甚至更高),Linux系统默认可能是1ms,但也会有波动;
  • 当你调用sleep(1)时,线程会被挂起,直到下一次时钟中断到来才会被唤醒,所以实际休眠时间往往是操作系统时钟粒度的整数倍,远大于你指定的1ms。

你可以单独跑一段循环调用Thread.sleep(1)的代码,统计1000次的总耗时,肯定会发现结果远大于1000ms。

2. 结合你的代码分析耗时差异

看你的代码,每个线程的process方法会循环1000次,每次调用stage1()和stage2(),每个方法里都有一次Thread.sleep(1)——也就是说每个线程要执行2000次sleep操作。

假设你的系统每次sleep实际耗时2ms(已经是比较乐观的情况),单线程执行总耗时大概是2000*2=4000ms(4秒)。那你用了两个线程,按道理应该可以并行执行(因为stage1用lock1,stage2用lock2,两个线程的stage1和stage2可以同时跑),为什么总耗时还是4秒?

这里还有个容易忽略的细节:你的两个线程共享同一个Random实例!Random.nextInt()方法虽然线程安全,但它内部是用CAS操作实现的,高并发下会有竞争开销,导致两个线程的执行互相拖慢,没办法完全并行。

再看你补充的循环1次的情况:总耗时6~8ms,这也完全符合我们的分析——两次sleep的实际耗时加起来,再加上线程启动、调度的额外开销,远大于理论上的2ms。

3. 为什么教程里只需要2秒?

大概率是教程的测试环境和你的不一样:

  • 教程用的操作系统时钟粒度更细(比如Linux系统开启了高精度时钟,或者修改了调度参数),sleep(1)的实际耗时更接近1ms;
  • 或者教程里的代码没有共享Random实例,两个线程可以完全并行,总耗时接近单线程的一半;
  • 甚至有可能教程里的sleep只是模拟耗时,实际用的是自旋等待这类更精确的方式,而不是真正的Thread.sleep。

验证方法

你可以做几个小实验来验证我的说法:

  • 把Random实例改成每个线程单独持有,看看总耗时会不会降低;
  • 把Thread.sleep(1)换成LockSupport.parkNanos(1000000)(1ms对应的纳秒数),看看实际耗时会不会更接近预期;
  • 在Linux系统上运行代码,对比Windows下的耗时差异。

备注:内容来源于stack exchange,提问作者mohamedesam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 11:44:31