问题描述
如何在 Java 中实现准确计时?我知道 Thread.sleep() 不准确并导致 InterruptedExceptions.我正在尝试制作一个物理模拟器,我想要准确的代码.到目前为止,这是我的代码:
public class FreeFall() {公共静态无效主(字符串 [] args){双高度 = Double.parseDouble(args[0]);双 xi = 高度;整数计数器 = 0;而(真){高度 = xi + 9.8/* 计数器 * 计数器;System.out.println(高度);计数器++;线程睡眠(1000);}}}
tl;dr
Java 的传统实现不是实时系统.所以你不能指望确定性的性能.
如果您坚持确定性时间,请寻找 实时 Java 的实现.
类似问题:Java - thread.sleep 的替代方案
Thread.sleep
您可以要求以纳秒分辨率进行睡眠,但由于当前计算机硬件的限制,您可能无法获得它.请参阅其他sleep
方法 以纳秒为单位采用第二个参数.
Thread.sleep( 0L , 300L ) ;//要求睡眠 300 纳秒.
Thread.sleep
的行为永远不是确定性可靠的,如下所述.CPU内部调度(如乱序执行、超线程)、JVM的OS调度、JVM对线程的调度、偶尔的垃圾回收等诸多因素都会影响实际的执行时间.因此,除非您转向 实时 Java 实现,否则您永远不能指望可预测的执行.
System.nanoTime
要跟踪经过的时间,请调用 System.nanoTime
.这具有纳秒的分辨率,但精度不太可能.截至 2018 年,传统的计算机硬件时钟只能精确到微秒左右的范围,而不是纳秒.这对于诸如微基准测试之类的事情很有用(提示:JMH).System.nanoTime
与告诉当前日期时间无关.返回的数字是某个未记录的原始时刻的计数(根据我的经验,自 JVM 启动以来,但不能保证).连续运行几十年,64 位数字可能会溢出.
long start = System.nanoTime() ;//只是一些逐渐增加的纳秒数.不是当前的日期时间.长停 = System.nanoTime() ;时间长了=(停止-开始);//以纳秒级的分辨率计算经过的时间(尽管不太可能精确到微秒级以上).
即时
要以 纳秒 的分辨率获取 UTC 中的当前时刻,请使用 java.time.Instant
班级.在 Java 8 中,当前时刻只能捕获到毫秒,但在 Java 9 和更高版本中,Clock/code>
可能会提供更精细的分辨率.我看到 微秒 在 macOS Sierra 上的 Oracle JDK 9.0.4 中捕获.
Instant Instant = Instant.now() ;//以纳秒的分辨率捕获 UTC 中的当前时刻,尽管精度可能不那么好.
2018-03-16T01:18:54.898583Z
持续时间
我建议一般使用 Instant
对象原样.您可以通过 isBefore
、isAfter
和 equals
方法.要计算经过的时间,请使用 Duration.between
.
Duration d = Duration.between( instantThen , Instant.now() ) ;//不附加到时间线的时间跨度,分辨率为纳秒.
避免System.currentTimeMillis ()
至于System.currentTimeMillis ()
,你可以忘记这个方法.您最好改用 Instant
.
执行者
至于定时器
和 TimerTask
,您应该知道这些类现在是遗留的,被 Java 5 及更高版本中添加的更复杂的 Executor 框架所取代.请参阅Oracle 教程.
实时 Java
即使使用 Executors,您也不能期望在执行中达到精确的分秒精度.主机操作系统控制 JVM 的调度,其性能可能会有所不同.在 JVM 中,线程是动态调度的,它们的性能可能会有所不同.特别是,垃圾收集可能会在特定时刻影响性能.
如果您想要确定性的执行时间,您需要获得 实时 Java一>.Java 的传统实现(例如 Oracle JDK 和 OpenJDK)肯定不是实时系统.
关于java.time
java.time 框架内置于 Java 8 及更高版本中.这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date
, Calendar
, &SimpleDateFormat
.
Joda-Time 项目,现在在 维护模式,建议迁移到 java.time 类.
要了解更多信息,请参阅 Oracle 教程.并在 Stack Overflow 上搜索许多示例和解释.规范是 JSR 310.
您可以直接与您的数据库交换 java.time 对象.使用符合 JDBC 驱动程序/jeps/170" rel="nofollow noreferrer">JDBC 4.2 或更高版本.不需要字符串,不需要 java.sql.*
类.
从哪里获取 java.time 类?
- Java SE 8、Java SE 9 及更高版本
- 内置.
- 具有捆绑实现的标准 Java API 的一部分.
- Java 9 添加了一些小功能和修复.
- Java SE 6 和 Java SE 7
- 大部分 java.time 功能已向后移植到 Java 6 &ThreeTen-Backport 中的 7 个.
- Android
- java.time 类的更高版本的 Android 包实现.
- 对于早期的 Android (ThreeTenABP 项目适应 ThreeTen-Backport(如上所述).请参阅如何使用 ThreeTenABP....
ThreeTen-Extra 项目扩展了 java.time与额外的课程.该项目是未来可能添加到 java.time 的试验场.您可能会在这里找到一些有用的类,例如 间隔
,YearWeek
, YearQuarter
和 更多.
How can I achieve accurate timing in Java? I know Thread.sleep() is inaccurate and leads to InterruptedExceptions. I'm trying to make a physics simulator and I want to have accurate code.Here is my code so far:
public class FreeFall() {
public static void main(String[] args) {
double height = Double.parseDouble(args[0]);
double xi = height;
int counter = 0;
while (true) {
height = xi + 9.8 / * counter * counter;
System.out.println(height);
counter++;
Thread.sleep(1000);
}
}
}
tl;dr
Conventional implementations of Java are not real-time systems. So you cannot count on deterministic performance.
If you insist on deterministic timing, seek out an implementation of real-time Java.
Similar Question: Java - alternative to thread.sleep
Thread.sleep
You can ask for sleeping with a resolution of nanoseconds, but you may not get it due to limitations of current computer hardware. See the other sleep
method taking a second argument for nanoseconds.
Thread.sleep( 0L , 300L ) ; // Ask to sleep 300 nanoseconds.
The behavior of Thread.sleep
is never deterministically reliable, as discussed below. Many factors such as internal CPU scheduling (such as out-of-order execution and hyper-threading), OS scheduling of the JVM, the JVM’s scheduling of threads, and occasional garbage collection all impact the actual execution timing. So you can never count on predictable execution unless you move to a real-time Java implementation.
System.nanoTime
To track elapsed time, call System.nanoTime
. This has a resolution of nanoseconds, but not likely precision. As of 2018, conventional computer hardware clocks are only accurate to a range of around microseconds, not nanoseconds. This is good for things such a micro-benchmarking (tip: JMH). The System.nanoTime
has nothing to do with telling the current date-time. The number returned is a count from some undocumented origin moment (in my experience, since the JVM launched, but not guaranteed). The 64-bit number may overrun in a few decades of continual running.
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
To get the current moment in UTC with a resolution of nanoseconds, use java.time.Instant
class. In Java 8, the current moment could captured only to milliseconds, but in Java 9 and later a fresh implementation of Clock
may deliver finer resolution. I am seeing microseconds captured in Oracle JDK 9.0.4 on macOS Sierra.
Instant instant = Instant.now() ; // Capture the current moment in UTC with a resolution of nanoseconds though likely with precision not as fine.
Duration
I suggest generally using the Instant
objects as-is. You can compare via isBefore
, isAfter
, and equals
methods. To calculate elapsed time, use Duration.between
.
Duration d = Duration.between( instantThen , Instant.now() ) ; // A span of time not attached to the timeline, with a resolution of nanoseconds.
Avoid System.currentTimeMillis()
As for System.currentTimeMillis()
, you can forget about this method. You are better off using Instant
instead.
Executor
As for Timer
and TimerTask
, you should know that those classes are now legacy, supplanted by the more sophisticated Executor framework added to Java 5 and later. See the Oracle Tutorial.
Real-time Java
Even with Executors, you cannot expect exact split-second accuracy in execution. The host OS controls scheduling the JVM, and its performance may vary. Within the JVM, threads are scheduled dynamically, and their performance may vary. In particular, garbage collection may impact performance at particular moments.
If you want deterministic timing of execution, you need to obtain an implementation of real-time Java. The conventional implementations of Java such as the Oracle JDK and OpenJDK are most certainly not real-time systems.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
这篇关于java中的准确计时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!