4

这个问题与基准无关。

我有一个 java 线程周期,它应该在接近一个时间段 T 时运行:

public class MyRunnable implements Runnable {

    private final long period = 10000L; //period T, in this case 10 secs

    public void run() {
        while() {
            long startTime = this.getTime();

            this.doStuff();

            long endTime = this.getTime();
            long executionTime = endTime - startTime;
            if(executionTime < this.period) {
                long sleepTime = (this.period - executionTime);
                try {
                     Thread.sleep(sleepTime);
                } catch(InterruptedException iex) {/*handle iex*/}
            }
        }
    }

    private long getTime() {
        return System.currentTimeMillis();
    }

    private void doStuff() {/*do stuff*/}

} 

当然,根据计划优先选择,Thread.sleep(sleepTime)可能略大于sleepTime. 但是,平均而言,这种方法提供了周期 T 的接近平均近似值。

问题

方法:

private long getTime() {
    return System.currentTimeMillis();
}

提供挂钟参考时间。如果机器的时钟向前或向后改变,则此实现无法提供周期 T 的近似值。例如:

long t1 = getTime();
Thread.sleep(30000);
long t2 = getTime();
System.out.println(t2 - t1);

Thread.sleep(30000)如果有人在“运行”时提前三分钟手动更改时钟,则会打印类似 204283 的内容。

由于系统时钟总是在变化(时间服务器同步、系统负载、用户设置等),因此使用System.currentTimeMillis()不足以满足我的需求。

失败的解决方案

为了提供更强大的时间参考,我尝试了以下 getTime 方法的实现:

long getTime() {
    long result;
    ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
    if (mxBean.isThreadCpuTimeSupported()) {
        result = mxBean.getCurrentThreadCpuTime()/1000000L;
    } else {
        throw new RuntimeException("unsupported thread cpu time");
    }
    return result;
}

问题getCurrentThreadCpuTime在于,产生的时间量是线程消耗的 CPU 时间,而不是那一刻剩下的时间。不考虑线程休眠或阻塞的剩余时间。例如:

long t1 = getTime();
Thread.sleep(30000);
long t2 = getTime();
System.out.println(t2 - t1);

getCurrentThreadCpuTimegetTime 的实现令人惊讶地打印“0”(零) 。

我想要的是

我想我需要的是这样的:

private long getTime() {
    long cpuCycles = getAmountOfCPUCyclesSinceTheProgramStarted();
    long cpuFrequency = getCPUFrequency();
    long result = cpuCycles / cpuFrequency;
    return result;
}

问题是我没有找到一种实现跨平台方式getAmountOfCPUCyclesSinceTheProgramStarted()的java方法。getCPUFrequency()

最后,我的问题是:如何以可靠的跨平台方式获取java中方法的花费时间?

4

1 回答 1

4

尝试使用System.nanoTime(),它似乎是您正在寻找的。

文档:

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。

于 2017-12-28T20:37:19.817 回答