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
相关产品推荐
相关产品推荐

