tl;博士
Java 的传统实现不是实时系统。所以你不能指望确定性的性能。
如果您坚持确定性时序,请寻求real-time Java 的实现。
类似问题:Java - alternative to thread.sleep
Thread.sleep
您可以要求以纳秒的分辨率进行睡眠,但由于当前计算机硬件的限制,您可能无法获得。请参阅the other sleep method 将第二个参数用于纳秒。
Thread.sleep( 0L , 300L ) ; // Ask to sleep 300 nanoseconds.
Thread.sleep 的行为从来都不是确定性可靠的,如下所述。内部 CPU 调度(如乱序执行和超线程)、JVM 的 OS 调度、JVM 对线程的调度、偶尔的垃圾回收等诸多因素都会影响实际的执行时序。因此,除非您转向 real-time Java 实现,否则您永远不能指望可预测的执行。
System.nanoTime
要跟踪经过的时间,请致电System.nanoTime。这具有纳秒级的分辨率,但不太可能精确。截至 2018 年,传统的计算机硬件时钟只能精确到大约微秒,而不是纳秒。这适用于微基准测试(提示:JMH)。 System.nanoTime 与告知当前日期时间无关。返回的数字是来自一些未记录的原始时刻的计数(根据我的经验,自 JVM 启动以来,但不能保证)。 64 位的数字在连续运行几十年后可能会溢出。
long start = System.nanoTime() ; // Just some progressively incrementing number of nanoseconds. NOT the current date-time.
long stop = System.nanoTime() ;
long elapsed = ( stop - start ) ; // Calculate elapsed time in a resolution as fine as nanoseconds (though not likely precise beyond microseconds).
Instant
要以nanoseconds 的分辨率获取UTC 的当前时刻,请使用java.time.Instant 类。在 Java 8 中,当前时刻只能捕获到毫秒,但在 Java 9 及更高版本中,Clock 中的fresh implementation 可能会提供更精细的分辨率。我看到microseconds 在 macOS Sierra 上的 Oracle JDK 9.0.4 中捕获。
Instant instant = Instant.now() ; // Capture the current moment in UTC with a resolution of nanoseconds though likely with precision not as fine.
2018-03-16T01:18:54.898583Z
Duration
我建议通常按原样使用Instant 对象。您可以通过isBefore、isAfter 和equals 方法进行比较。要计算经过的时间,请使用Duration.between。
Duration d = Duration.between( instantThen , Instant.now() ) ; // A span of time not attached to the timeline, with a resolution of nanoseconds.
避免System.currentTimeMillis()
至于System.currentTimeMillis(),你可以忘记这个方法。你最好改用Instant。
执行者
至于Timer 和TimerTask,您应该知道这些类现在是遗留的,被添加到Java 5 及更高版本的更复杂的Executor 框架所取代。见the Oracle Tutorial。
实时 Java
即使使用 Executors,您也不能期望在执行过程中获得精确的瞬间准确性。主机操作系统控制 JVM 的调度,其性能可能会有所不同。在 JVM 中,线程是动态调度的,它们的性能可能会有所不同。特别是,垃圾收集可能会影响特定时刻的性能。
如果您想要确定的执行时间,您需要获得real-time Java 的实现。 Java 的传统实现,例如 Oracle JDK 和 OpenJDK,肯定是不是real-time systems。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。