关于Java 获取时间戳的方法,我和同事争论了半天~

共 3370字,需浏览 7分钟

 ·

2022-03-15 15:24

  

程序员的成长之路
互联网/程序员/技术/资料共享 
关注


阅读本文大概需要 2.8 分钟。

来自:https://segmentfault.com/blog/yidinghe


Java有两个取时间戳的方法:System.currentTimeMillis() 和 System.nanoTime(),它们的使用场景是有区别的,当前网上一些文章对于这两个方法的性能讨论存在一些片面的描述,本文希望能给出一个简单的最终答案。

# System.currentTimeMillis() 存在性能问题?


答案是否定的。

这两个方法性能差异取决于操作系统。

Windows:

在 Windows 下,System.currentTimeMillis() 比 System.nanoTime() 要快很多,这是因为 Windows 系统为前者提供的只是一个缓存变量,而后者则是实时的去硬件底层获取计数。

  • 参考1: https://stackoverflow.com/questions/5839152/why-do-system-nanotime-and-system-currenttimemillis-drift-apart-so-rapidly/5839267#5839267

  • 参考2: http://stas-blogspot.blogspot.com/2012/02/what-is-behind-systemnanotime.html


所以如果你的生产环境是 Windows,请尽可能避免使用 System.nanoTime()。

Linux:

在 Linux 下,两者的执行耗时相差不大,不论是单线程还是多线程。

# 不同的虚拟机实现会带来性能差异


如今的云主机主要有 Xen 和 KVM 两种实现方式,网上有文章发现它们在取系统时间方面存在性能差异。

文章地址:https://www.javaadvent.com/2019/12/measuring-time-from-java-to-kernel-and-back.html

当你的虚拟机用的是 Xen 时,取时间的耗时会是 KVM 的十倍以上。不过上文也提供了遇到此类问题该如何解决的方案。


# 需要写一个专门的类来提升 System.currentTimeMillis() 性能吗?


不需要。那属于画蛇添足。

# 我的测试代码


我的测试代码如下,没有任何依赖,可以直接用 javac 编译然后运行。读者有兴趣可以试试:

import java.util.ArrayList;import java.util.List;import java.util.function.Consumer;
public class TimePerformance {
public static final int LOOP_COUNT = 9999999; public static final int THREAD_COUNT = 30;
public static void main(String[] args) {
Runnable millisTest = () -> {
long start = System.currentTimeMillis(); for (int i = 0; i < LOOP_COUNT; i++) { System.currentTimeMillis(); } long end = System.currentTimeMillis();
System.out.printf("%s : %f ns per call\n", Thread.currentThread().getName(), ((double)end - start) * 1000000 / LOOP_COUNT); };
Runnable nanoTest = () -> {
long start = System.currentTimeMillis(); for (int i = 0; i < LOOP_COUNT; i++) { System.nanoTime(); } long end = System.currentTimeMillis();
            System.out.printf("%s : %f ns per call\n", Thread.currentThread().getName(), ((double)end - start) * 1000000 / LOOP_COUNT); };
Consumer testing = test -> { System.out.println("Single thread test:"); test.run();
System.out.println(THREAD_COUNT + " threads test:"); List threads = new ArrayList<>(); for (int i = 0; i < THREAD_COUNT; i++) { Thread t = new Thread(test); t.start(); threads.add(t); } // Wait for all threads to finish threads.forEach(thread -> { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); };
System.out.println("//// Test System.nanoTime()"); testing.accept(nanoTest); System.out.println("//// Test System.currentTimeMillis()"); testing.accept(millisTest); }}

因为我用的是 Windows,所以执行输出当中 System.nanoTime() 明显非常慢。具体输出内容我就不放出来了,因为不具有参考价值,大多数生产环境用的是 Linux。

推荐阅读:

乌克兰:“我要拔俄罗斯的网线”,ICANN:“不可以!”

干掉Random:这个类已经成为获取随机数的王者

互联网初中高级大厂面试题(9个G)

内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper、数据结构、限流熔断降级......等技术栈!

戳阅读原文领取!                                  朕已阅 

浏览 43
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报