繁体   English   中英

Java中的准确计时

[英]Accurate timing in java

如何在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);
        }
    }
}

您可能想利用时间戳,利用System.currentTimeMillis() ,它会给您自1970年1月1日起经过的毫秒数。

当对象开始掉落时,请加上时间戳记。 然后,在循环中,您可以使用代表当前时间的时间戳记。 currentTime减去startTime ,您将获得准确的毫秒数。 例如,通过此计算,您可以计算出在给定速度下该对象在该时间段内应下落的距离。

这种方法的好处在于,无论运行在快速还是慢速的处理器上都没有关系,因为时间戳反映了实际的时间流逝与循环迭代次数之间的关系。

TL;博士

Java的常规实现不是实时系统。 因此, 您不能指望确定性性能

如果您坚持确定性时序,请寻求实时Java的实现

相似的问题: Java-替代thread.sleep

Thread.sleep

您可以要求睡眠时间为纳秒级,但是由于当前计算机硬件的限制,您可能无法入睡。 请参阅另一个sleep方法 ,将第二个参数设为纳秒。

Thread.sleep( 0L , 300L ) ;  // Ask to sleep 300 nanoseconds.

如下所述, Thread.sleep的行为永远不会确定可靠。 内部CPU调度(例如乱序执行和超线程),JVM的OS调度,JVM的线程调度以及偶尔的垃圾回收等许多因素都会影响实际的执行时间。 因此,除非移至实时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

要获得UTC的当前时刻,分辨率为纳秒 ,使用java.time.Instant类。 在Java 8中,当前时刻只能捕获到毫秒,但是在Java 9及更高版本中, Clock全新实现可以提供更高的分辨率。 我看到在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对象。 您可以通过isBeforeisAfterequals方法进行比较。 要计算经过的时间,请使用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

执行者

至于TimerTimerTask ,您应该知道这些类现在是遗留的,被Java 5和更高版本中添加的更复杂的Executor框架所取代。 请参阅《 Oracle教程》

实时Java

即使使用执行器,您也无法期望执行过程中具有精确的瞬间精度。 主机OS控制调度JVM,其性能可能会有所不同。 在JVM中,线程是动态调度的,它们的性能可能会有所不同。 特别是,垃圾收集可能会在特定时刻影响性能。

如果您需要确定的执行时间,则需要获取实时Java的实现 当然,诸如Oracle JDK和OpenJDK之类的Java常规实现绝非 实时系统


关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参见Oracle教程 并在Stack Overflow中搜索许多示例和说明。 规格为JSR 310

您可以直接与数据库交换java.time对象。 使用与JDBC 4.2或更高版本兼容的JDBC驱动程序 不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

  • Java SE 8Java SE 9和更高版本
    • 内置。
    • 标准Java API的一部分,具有捆绑的实现。
    • Java 9添加了一些次要功能和修复。
  • Java SE 6Java SE 7
    • java.time的许多功能在ThreeTen- Backport中都被反向移植到Java 6和7。
  • Android的
    • 更高版本的Android捆绑了java.time类的实现。
    • 对于早期的Android(<26), ThreeTenABP项目改编了ThreeTen-Backport (如上所述)。 请参阅如何使用ThreeTenABP…

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目为将来可能在java.time中添加内容提供了一个试验场。 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

对于Java 8及更高版本-您可以使用java.time库,它具有日期时间类

对于日期-

  //To create a new date
LocalDate ld =  LocalDate.Of(2018,March,26);
   //To print current date
LocalDate.now();

对于时间-

 //To create a new time
LocalTime lt = LocalTime.Of(11,22);
   //To print current time
Local time.now();

对于日期和时间-

   //To create a new date time
LocalDateTime ldt = LocalDateTime.Of(2018,March,26,11,22);
   //To print current date time
LocalDateTime.now();

注意:请注意以下事项-这些类仅在Java 8及更高版本中可用。 -这些类具有私有构造函数,因此您无法实例化它们-Of是静态方法,因此使用类名进行调用-这些类是不可变的,因此您需要创建的任何更新都将保存到新对象中

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM