哪个更推荐:Instant.now().toEpochMilli()还是System.currentTimeMillis()?

33
在Java中,获取当前时间戳有很多不同的方法,但哪一种方式是建议使用的呢:Instant.now().toEpochMilli()还是System.currentTimeMillis()

3
定义更好?更高效?我敢打赌它们的表现是一样的。更易读?那只是个人观点。但是,我认为两者都比 Calendar.getInstance().getTimeInMillis() 更好。 - Elliott Frisch
就性能而言,System.currentTimeMillis() 应该更快,因为它没有对象创建的开销。就精度而言,在某些支持微秒分辨率的平台上,Instant 方法可能更好。 - Meno Hochschild
@ElliottFrisch 我已经改了措辞 :-D - Yishu Fang
2
真正的问题是你为什么要获取时间戳?如果你想计时,那么 System.nanoTime() 可能是更好的选择(如果你需要精度)。我可能会寻找一个更高级别的抽象;比如 StopWatch - Elliott Frisch
@Holger System.currentTimeMillis() 的真实分辨率甚至可能达到10毫秒或更差。它也更容易受到操作系统时钟更改的影响(例如重新连接到NPT服务器)。 - Meno Hochschild
显示剩余8条评论
4个回答

19

两种方法都可以使用。但是除了少数情况之外,均不建议使用。

你需要Epoch时间的毫秒级精度,为什么?

在Java中,我们可以有许多不同的方法来获取当前时间戳,

要获取当前时间戳,只需使用Instant.now()即可。无需转换为毫秒。

Java最初几年中的许多方法,以及标准库中的许多方法,都使用自纪元以来的long毫秒数作为参数。但是,今天我会认为这是老式的。请尝试查找或创建一个更现代的方法,例如将Instant作为参数。面向对象编程,不要使用基本类型long。它将使您的代码更清晰易懂。

如Eliott Frisch在评论中所说,如果这是用于测量经过的时间,则可能更喜欢System.nanoTime()的更高分辨率。

如果你确实需要自纪元以来的毫秒数

假设您有充分的理由想要计算自纪元以来的毫秒数,...

哪个更推荐:Instant.now().toEpochMilli() 或者 System.currentTimeMillis()

不同的人有不同的看法。有些人认为应该使用现代的日期和时间API:java.time来处理所有日期和时间工作,这意味着在此处应该使用Instant。通常使用java.time是一个好习惯,因为Java 1.0和1.1的日期和时间类(DateCalendarTimeZoneDateFormatSimpleDateFormat等)设计得很差并已经过时,我们不能再使用它们了。

另一方面,我不知道System.currentTimeMillis()有任何设计问题(除了上面提到的使用毫秒计数的long类型问题,这显然是Instant.now().toEpochMilli()System.currentTimeMillis()共有的)。

如果两者之间存在轻微的性能差异,我很难想象出哪种情况下这会有影响。

在你的情境中,选择你认为更易读和不会引起意外的选项。

类似的问题


3
我想补充一下Instant.now()的另一个优点,那就是你可以使用JMockit这样的工具来模拟它。System.currentTimeMillis()是一个本地方法,因此通常无法模拟。 - fool4jesus
对于低延迟的Java应用程序,使用像“long”这样的原始数据类型会更好。使用Long类会很昂贵,并且在内存中占用更多的字节;并且会创建更多的垃圾。少量的垃圾意味着高性能。更多的垃圾意味着高延迟。 - alpha
1
@alpha 稍微好一些,确实如此,但是更好吗?我无法想象。你有什么测量数据来支持你的说法吗?Java在垃圾收集短暂对象方面非常出色。我同意,如果你真的想进行微小优化,这里有一些潜力。(我绝不建议使用任何Long对象。) - Ole V.V.
是的,我确实对原始类型和封装对象进行了一些性能测试。即,如果使用原始类型,则方法调用使用堆栈内存,因此不会创建垃圾。封装对象存储在堆中。同时,长整型数组分配在同一块内存中,而Long类型的数组则不是。 - alpha

5
就我所知,我进行了一个快速的非理想性能测试,比较了这两种方法。
在我的系统上(Ubuntu 20.04,OpenJDK 17.0.4),运行 System.currentTimeMillis 十百万次大约需要230毫秒,而运行 Instant.now().toEpochMilli() 十百万次大约需要370毫秒。
import java.time.Instant;

public class A { 
   public static void main(String[] args) {
       long a = 0;
       long start = System.currentTimeMillis();
       for (int i = 0; i < 10_000_000; i++) {
           //a += Instant.now().toEpochMilli();
           a += System.currentTimeMillis();
       }
       System.out.println(a);
       System.out.println(System.currentTimeMillis() - start);
   }   
}

5
据我所知,自Java-8起,建议使用Instant,因此Instant.now().toEpochMilli()更好。同时,它基于时间轴工作,表示该时间轴上的特定时刻。
对于java.lang.System.currentTimeMillis()方法,它返回当前时间的毫秒数。该值的粒度取决于底层操作系统,并且可能更大。
因此,为了保持一致性,应全部使用Instant

1
你能添加一个链接来引用“Instant”被推荐的地方吗? - Eric

4

我想补充说明的是,System.nanoTime() 更多地关注于准确性而非精度。

System.currentTimeMillis() 基于系统时钟,大部分情况下基于计算机内的石英钟。它不准确且会漂移。(虚拟机更糟糕,因为您没有物理时钟,必须与主机同步)当您的计算机将此石英钟与全球时钟同步时,您甚至可能观察到您的时钟向后/向前跳动,因为您的本地时钟太快或太慢。

另一方面,System.nanoTime() 基于单调时钟。这个时钟与人类所说的实际时间无关。它只以恒定的速度向前移动。它不像石英钟那样漂移,也不需要同步。这就是为什么它非常适合用来测量经过的时间。


2
所有的时钟都不能漂移吗?那么 System.nanoTime() 应该如何避免它呢? - Ole V.V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接