如何在Java中实现准确的计时?我知道Thread.sleep()是不准确的,并导致InterruptedExceptions。我正在尝试制作一个物理模拟器,我想拥有准确的代码。 到目前为止,这是我的代码:
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);
}
}
}
答案 0 :(得分:2)
您可能希望利用时间戳,利用System.currentTimeMillis()
,这将为您提供自1970年1月1日以来经过的毫秒数。
在对象开始下降时记下时间戳。然后,在循环中,您可以获取表示当前时间的时间戳。从startTime
中减去currentTime
,您就会获得准确的毫秒数。例如,在此情况下,您可以计算出在恒定速度下,您的物体在该段时间内应该下降的距离。
这种方法的好处在于,您是否在快速或慢速处理器上运行并不重要,因为您的时间戳反映了实际的时间流逝与循环的迭代次数之间的关系
答案 1 :(得分:2)
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
nothing 。返回的数字来自一些未记录的原始时刻(根据我的经验,自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
要以UTC nanoseconds的分辨率获取UTC中的当前时刻,请使用java.time.Instant
类。在Java 8中,当前时刻只能捕获几毫秒,但在Java 9及更高版本中,fresh implementation Clock
可以提供更精细的分辨率。我在MacOS Sierra的Oracle JDK 9.0.4中看到了microseconds。
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。
即使使用Executors,您也无法在执行中获得精确的分秒精度。主机OS控制JVM的调度,其性能可能会有所不同。在JVM中,线程是动态调度的,它们的性能可能会有所不同。特别是,垃圾收集可能会影响特定时刻的性能。
如果您想要确定性的执行时间,则需要获得real-time Java的实现。 Java的传统实现,例如Oracle JDK和OpenJDK,肯定是不是 real-time systems。
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 driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:0)
For Java 8 and above - You can use java.time library It has date time classes
For Date -
//To create a new date
LocalDate ld = LocalDate.Of(2018,March,26);
//To print current date
LocalDate.now();
For Time -
//To create a new time
LocalTime lt = LocalTime.Of(11,22);
//To print current time
Local time.now();
For both Date and Time -
//To create a new date time
LocalDateTime ldt = LocalDateTime.Of(2018,March,26,11,22);
//To print current date time
LocalDateTime.now();
Note : Please take care of these things - -These classes are only available in Java 8 and above. -These classes has private constructor, so you can't instantiate them -Of is a static method and hence called using class name -These classes are immutable, and hence any update you need to create is to saved into a new object