System.currentTimeMillis() 和 System.nanoTime() 哪个更快?别用错了! ...

守听  金牌会员 | 2022-8-22 06:12:42 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 878|帖子 878|积分 2634

作者:捏造的信仰
来源:https://segmentfault.com/a/1190000041276485
Java有两个取时间戳的方法:System.currentTimeMillis() 和 System.nanoTime(),它们的使用场景是有区别的,当前网上一些文章对于这两个方法的性能讨论存在一些片面的描述,本文希望能给出一个简单的最终答案。
System.currentTimeMillis() 存在性能问题?

答案是否定的。这两个方法性能差异取决于操作系统。
Windows:
在 Windows 下,System.currentTimeMillis() 比 System.nanoTime() 要快很多,这是因为 Windows 系统为前者提供的只是一个缓存变量,而后者则是实时的去硬件底层获取计数。
所以如果你的生产环境是 Windows,请尽可能避免使用 System.nanoTime()。
Linux:
在 Linux 下,两者的执行耗时相差不大,不论是单线程还是多线程。
不同的虚拟机实现会带来性能差异

如今的云主机主要有 Xen 和 KVM 两种实现方式,网上有文章发现它们在取系统时间方面存在性能差异。
当你的虚拟机用的是 Xen 时,取时间的耗时会是 KVM 的十倍以上。不过上文也提供了遇到此类问题该如何解决的方案。
需要写一个专门的类来提升 System.currentTimeMillis() 性能吗?

不需要。那属于画蛇添足。
我的测试代码

我的测试代码如下,没有任何依赖,可以直接用 javac 编译然后运行。读者有兴趣可以试试:
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.function.Consumer;
  4. public class TimePerformance {
  5.     public static final int LOOP_COUNT = 9999999;
  6.     public static final int THREAD_COUNT = 30;
  7.     public static void main(String[] args) {
  8.         Runnable millisTest = () -> {
  9.             long start = System.currentTimeMillis();
  10.             for (int i = 0; i < LOOP_COUNT; i++) {
  11.                 System.currentTimeMillis();
  12.             }
  13.             long end = System.currentTimeMillis();
  14.             System.out.printf("%s : %f ns per call\n",
  15.                     Thread.currentThread().getName(), ((double)end - start) * 1000000 / LOOP_COUNT);
  16.         };
  17.         Runnable nanoTest = () -> {
  18.             long start = System.currentTimeMillis();
  19.             for (int i = 0; i < LOOP_COUNT; i++) {
  20.                 System.nanoTime();
  21.             }
  22.             long end = System.currentTimeMillis();
  23.             System.out.printf("%s : %f ns per call\n",
  24.                     Thread.currentThread().getName(), ((double)end - start) * 1000000 / LOOP_COUNT);
  25.         };
  26.         Consumer<Runnable> testing = test -> {
  27.             System.out.println("Single thread test:");
  28.             test.run();
  29.             System.out.println(THREAD_COUNT + " threads test:");
  30.             List<Thread> threads = new ArrayList<>();
  31.             for (int i = 0; i < THREAD_COUNT; i++) {
  32.                 Thread t = new Thread(test);
  33.                 t.start();
  34.                 threads.add(t);
  35.             }
  36.             // Wait for all threads to finish
  37.             threads.forEach(thread -> {
  38.                 try {
  39.                     thread.join();
  40.                 } catch (InterruptedException e) {
  41.                     e.printStackTrace();
  42.                 }
  43.             });
  44.         };
  45.         System.out.println("//// Test System.nanoTime()");
  46.         testing.accept(nanoTest);
  47.         System.out.println("//// Test System.currentTimeMillis()");
  48.         testing.accept(millisTest);
  49.     }
  50. }
复制代码
因为我用的是 Windows,所以执行输出当中 System.nanoTime() 明显非常慢。
具体输出内容我就不放出来了,因为不具有参考价值,大多数生产环境用的是 Linux。
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表