我有一个在Windows系统上运行的程序。逻辑如下。我看到线程正在睡眠60秒,但时间戳和打印持续时间是55秒。据我所知,Thread.sleep和System.currentTimeMillis都依赖于系统时间。为什么我会看到这种差异
public static void main(String[] args) throws InterruptedException {
logger.info("Started");
long start = System.currentTimeMillis();
logger.info("No Arguments passed waiting for 60 seconds....");
Thread.sleep(60000);
logger.info("Sleep Duration: " + (System.currentTimeMillis()-start));
logger.info("Ended");
}
答案 0 :(得分:1)
Thread.sleep导致当前正在执行的线程进入休眠状态 (暂时停止执行)指定的持续时间,但须遵守 系统定时器和调度程序的精度和准确性。线程 不会失去任何监视器的所有权,并恢复执行 将取决于调度和处理器的可用性 执行线程。
在任何情况下,您都不能假设调用sleep会在指定的时间段内暂停该线程。
答案 1 :(得分:1)
正如@Tagir_Valeev
所说,你的Windows调度程序并不是那么好,这是我猜的一个主要原因。
另一个原因是,在2个时间点之间有logger.info()
,可能需要几毫秒。
因此,按照以下方式编写程序可能会使其更准确。
SleepAccuracyTest.java:(一个TestNG
班级,使用Slf4j
作为记录器)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
// test sleep accuracy,
public class SleepAccuracyTest {
public static final int MAX_DIFF = 1; // max diff in milliseconds,
private Logger logger = LoggerFactory.getLogger(SleepAccuracyTest.class);
private int counter = 0;
@Test(invocationCount = 10, alwaysRun = true)
public void testIt() {
int during = 1000;
counter++;
try {
logger.info("Started [{}]", counter);
logger.info("No Arguments passed waiting for {} milliseconds...", during);
long start = System.currentTimeMillis();
Thread.sleep(during);
long end = System.currentTimeMillis();
long actualDuring = end - start;
long diff = actualDuring - during;
Assert.assertTrue(Math.abs(diff) <= MAX_DIFF);
logger.info("Expected during: {}, actual duration: {}, diff: {}", during, actualDuring, diff);
logger.info("Ended\n");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试结果:
在我的机器上( 64bit linux-3.16,Java8,4 cpu ):
因此,logger.info()
或System.out.printf()
部分也需要时间。
但只有几毫秒,从不秒。