1

我目前正在用 Java 编写一个多线程程序。在某些时候,不同的线程会记录他们的动作,我正在使用nanoTime它。每个线程都有自己的日志文件,最后我将它们合并并根据它们的时间(nanoTime)对它们进行排序以查看发生了什么。问题是我有与此类似的错误行为,其中x是一个volatile变量:

// logged by thead1
x = true // done at time 0000, time computed & logged after x = true was done

// no events in between

// logged by thread2
read x // reads false while time before reading is 0001

所以在我看来,这nanoTime并没有真正正确地计时。在nanoTime文档中是这样写的:

仅当在 Java 虚拟机的同一实例中获得的两个此类值之间的差异被计算时,此方法返回的值才有意义。

由同一进程创建的线程是否有可能在不同的 JVM 中执行?这可以解释错误行为,nanoTime但仍然没有太大意义。有任何想法吗?

4

2 回答 2

3

这完全取决于操作系统,但如果您有一个 CPU 插槽,您将无法使用 nanoTime 看到任何错误。如果您使用 Windows 7+ 或最新版本的 Linux,nanoTime 会更正套接字之间的差异。顺便说一句,如果你有一个多插槽 XP 盒子,你可以看到 nanoTime 前后跳跃几毫秒。(简而言之,不要在多插槽机器上使用 XP 并期望有好的结果)

另请注意,某些操作系统只有微秒分辨率。这意味着您可以在线程之间执行许多操作,并且它们似乎都具有相同的时间戳。解决方案是使用具有更高分辨率计时器的操作系统。这不涉及更改您的代码甚至您的 JVM。

由同一进程创建的线程是否有可能在不同的 JVM 中执行?

我不知道有什么方法可以做到这一点,我也想不出一个重要的原因。无论您使用的是哪个线程、JVM 或进程,都会进行相同的系统调用。

这可以解释 nanoTime 的错误行为,但仍然没有太大意义。有任何想法吗?

很可能您的操作系统上的调用 nanoTime() 调用只有微秒级的分辨率。

read x // 读取前的时间为 0001 时读取为 false

如果您的时间优于微秒,那么每次调用 nanoTime() 都可能不同。通过缓存更新 volatile 变量至少需要 75 个时钟周期或约 20 纳秒。没有什么是即时的,我已经看到线程之间的延迟接近 100 纳秒的延迟,用于线程之间的微不足道的更新。

于 2013-11-19T22:17:13.073 回答
0

我不知道期望 nanoTime 允许您以这种方式对发生在不同线程上的事件进行排序是否有效。我会重新考虑您的设计,每个线程都有一个单独的日志文件,您可以根据时间将其合并在一起。如果您使用的是 log4j,我会让它们写入同一个日志。

如果您正在构建自己的日志记录实现,我会让他们将他们的消息写入 a java.util.concurrent.LinkedBlockingQueue(不会有争用,我怀疑您试图通过让每个线程都有自己的日志来避免这种情况),并有另一个线程负责定期排出队列中可用的任何消息并将它们写入文件。

于 2013-11-19T22:38:25.853 回答