可靠的跨平台方式获取Java中的方法时间

时间:2017-12-28 19:40:41

标签: java multithreading thread-sleep system-clock cpu-time

这个问题与基准无关。

我有一个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)&#34;&#34;运行&#34;之前手动更改时钟,

会打印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);

令人惊讶的印刷品&#34; 0&#34; (零)由getCurrentThreadCpuTime getTime的实现。

我想要什么

我想我需要的是这样的东西:

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

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

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

1 个答案:

答案 0 :(得分:4)

尝试使用System.nanoTime(),它似乎就是你要找的东西。

来自the docs:

  

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