Thread.sleep() 针对小睡眠间隔的优化

Thread.sleep() optimization for small sleep intervals

我正在编写一个涉及调用者定义的时间分辨率的库。在实现中,这个值最终成为一些后台线程在做一些内务处理并再次返回睡眠之前将睡眠的间隔。我允许此分辨率小至 1 毫秒,转换为 Thread.sleep(1)。我的直觉是,这可能比忙等待 1 毫秒更浪费且更不精确。如果是这样的话;

  1. 我是否应该回退到忙等待足够小(多小)的时间间隔?
  2. 有谁知道 JVM 是否已经在进行这种优化,而我根本不需要做任何事情?

这很容易测试:

public class Test {

    static int i = 0;
    static long[] measurements = new long[0x100];
    
    static void report(long value) {
        measurements[i++ & 0xff] = value;
        if (i > 10_000) {
            for (long m : measurements) {
                System.out.println(m);
            }
            System.exit(0);
        }
    }
    
    static void sleepyWait() throws Exception {
        while (true) {
            long before = System.nanoTime();
            Thread.sleep(1);
            long now = System.nanoTime();
            report(now - before);
        }                   
    }
    
    static void busyWait() {
        while (true) {
            long before = System.nanoTime();
            long now;
            do {
                now = System.nanoTime();
            } while (before + 1_000_000 >= now);
            report(now - before);
        }
    }
    
    
    public static void main(String[] args) throws Exception {
        busyWait();
    }
}

运行 在我的 windows 系统上,这表明 busyWait 具有微秒精度,但完全使用一个 CPU 核心。

相比之下,sleepyWait 不会导致可测量的 CPU 负载,但只能达到毫秒级精度(通常需要 2 毫秒才能触发,而不是请求的 1 毫秒)。

至少在 windows 上,这是准确性和 CPU 使用之间的直接权衡。

还值得注意的是,通常有 运行 和 CPU 的替代方法,它们会全速检查时间。在许多情况下,您可能会等待一些其他信号,并且提供专注于 time-based 分辨率的 API 可能会将 API 的用户引向错误的方向。