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

Duration.isZero()返回false时,Duration.toMillis()是否可能返回0?

wait() 参数出现0的问题分析

为计算wait()的等待时长,我们提炼出核心逻辑代码如下:

Instant start = Instant.now();
while(!exiting) {
    synchronized(waitObject) {
        Duration toWait = TOTAL_WAIT_TIME.minus(Duration.between(start, Instant.now()));
        if (!toWait.isNegative() && !toWait.isZero()) { // 注:原代码此处缺少闭合括号,属于语法错误
            waitObject.wait(toWait.toMillis());
        }
    }
}

测试过程中发现,这段代码可能会向wait()方法传入0作为参数。

问题根源

  • 精度截断:Duration支持纳秒级精度,但wait(long)仅接受毫秒级参数。当toWait是小于1毫秒的正值时,!toWait.isZero()判断为true(实际时长非零),但toWait.toMillis()会被截断为0,导致调用wait(0)。
  • 时间窗口差:从计算toWait到调用wait()的间隙,系统时间持续流逝,可能让原本非零的toWait在转换为毫秒后变为0。

修正方案

方案1:基于毫秒值判断

直接判断转换后的毫秒数是否大于0,避免Duration精度与wait方法参数不匹配的问题:

Instant start = Instant.now();
while(!exiting) {
    synchronized(waitObject) {
        Duration toWait = TOTAL_WAIT_TIME.minus(Duration.between(start, Instant.now()));
        long waitMs = toWait.toMillis();
        if (waitMs > 0) {
            waitObject.wait(waitMs);
        }
        // 若waitMs<=0,可根据业务需求选择退出循环或其他处理
    }
}

方案2:保留纳秒精度

使用wait(long, int)重载方法,传入毫秒和纳秒部分,提升等待精度同时避免传入0的情况:

Instant start = Instant.now();
while(!exiting) {
    synchronized(waitObject) {
        Duration toWait = TOTAL_WAIT_TIME.minus(Duration.between(start, Instant.now()));
        if (!toWait.isNegative()) {
            waitObject.wait(toWait.toMillis(), toWait.getNano() % 1_000_000);
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 03:32:44