Linux上的Java:使用System.nanotime()为阻塞的线程测量经过的时间

时间:2013-12-13 01:23:16

标签: java linux benchmarking

我有一个从ArrayBlockingQueue() connectionPool.获取对象的线程如果ArrayBlockingQueue()为空,则该线程可能被阻塞。要测量调用线程被阻止的时间,我使用以下代码:

long start = System.nanoTime();
DataBaseEndPoint dbep = connectionPool.take();
long end = System.nanoTime();
long elapsed = (end - start)/1000000;

现在,我担心的是,未阻塞的线程可能会开始在多处理器计算机上的不同处理器上运行。在这种情况下,我不完全确定在不同的处理器上使用的'系统定时器'是否相同。 这篇博文(http://www.javacodegeeks.com/2012/02/what-is-behind-systemnanotime.html)表明Linux为每个处理器使用了不同的时间戳计数器(也用于System.nanotime()),这可能会破坏上面例子中的经过时间计算。

  

使用CLOCK_MONOTONIC标志从clock_gettime读取该值   使用TSC或HPET。与Windows的唯一区别是   Linux甚至没有尝试同步从不同CPU读取的TSC值,   它只是按原样返回它。这意味着价值可以回升   在读取它的CPU的依赖性下向前跳。

此链接(http://lwn.net/Articles/209101/)表明TSC不再用于高分辨率计时器。

  

...最近更新的高分辨率计时器和动态刻度补丁   set包括禁止使用TSC的更改。好像是   高分辨率计时器和动态刻度功能不兼容   TSC ......

那么,问题是,Linux机器目前使用什么来将值返回到System.nanotime()?并且,在上述情况下使用System.nanotime()安全来测量经过的时间(在另一个处理器上启动阻塞的线程)。如果不安全,还有什么选择?

1 个答案:

答案 0 :(得分:0)

虚拟机(以及一般生活)的一个重要因素是抽象。线程'执行时间根据核心数量而有所不同;不是在Linux中,也不是在Windows中......我希望我不会误解你的问题。

(虽然我使用的是currentTimeMillis(),但nanime在不同的范围内是相同的,当然)

检查我制作的以下示例:

public class SynchThreads {

    public static void main(String[] args) throws InterruptedException {
        GreedyTask gtA = new GreedyTask("A");
        GreedyTask gtB = new GreedyTask("B");
        Thread a = new Thread(gtA);
        Thread b = new Thread(gtB);
        a.start();
        b.start();
        a.join();
        b.join();
        System.out.println(gtA.toString()+" running time: "+gtA.getRunningTime());
        System.out.println(gtB.toString()+" running time: "+gtB.getRunningTime());
    }

    private static class GreedyTask implements Runnable {

        private long startedTime, finishedTime, totalRunTime;
        private String myName;

        public GreedyTask(String pstrName) {
            myName = pstrName;
        }

        public void run() {
            try {
                startedTime = System.currentTimeMillis();
                randomPowerNap(this);
                finishedTime = System.currentTimeMillis();
                totalRunTime = finishedTime - startedTime;
            } catch (Exception e) { System.err.println(e.getMessage()); }
        }

        public String toString() { return ("Task: " + myName); }
        public long getRunningTime() { return this.totalRunTime; }
    }

    private static synchronized void randomPowerNap(GreedyTask gt) throws       InterruptedException {
        System.out.println("Executing: "+gt.toString());
        long random = Math.round(Math.random()*15000);
        System.out.println("Random time for "+gt+" is: "+random);
        Thread.sleep(random);
    }
}

以下是4核Windows机器中运行的输出:

Executing: Task: A
Random time for Task: A is: 1225
Executing: Task: B
Random time for Task: B is: 4383
Task: A running time: 1226
Task: B running time: 5609 // what's funny about this? this is equal to Btime - Atime

这是在4核Linux机器上运行的:

Executing: Task: A
Random time for Task: A is: 13577
Executing: Task: B
Random time for Task: B is: 5340
Task: A running time: 13579
Task: B running time: 18920 // same results

结论:B总时间增加了当randomPowerNap被A阻塞时必须等待的时间,因此由于虚拟机的硬件抽象,线程看到它们的运行时间没有差异,因为它们都在&#39中运行如果你知道我的意思,那就是虚拟的核心。

我希望这会有所帮助。