前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java获取系统时间的正确方式

Java获取系统时间的正确方式

作者头像
码客说
发布2022-11-22 16:24:26
1K0
发布2022-11-22 16:24:26
举报
文章被收录于专栏:码客码客

前言

如果代码中获取时间使用的System.currentTimeMillis();,这样在单线程的情况下完全没问题,但是如果是多线程比如说后端提供的数据服务,那么就会出现严重的性能问题,导致服务不可用。

结论是

单线程执行System.currentTimeMillis();比多线程并发执行System.currentTimeMillis();快了许多倍。

为什么会这样?

来到HotSpot源码的hotspot/src/os/linux/vm/os_linux.cpp文件中,有一个javaTimeMillis()方法,这就是System.currentTimeMillis()的native实现。

简单来讲就是:

调用gettimeofday()需要从用户态切换到内核态;

gettimeofday()的表现受Linux系统的计时器(时钟源)影响,在HPET计时器下性能尤其差;

系统只有一个全局时钟源,高并发或频繁访问会造成严重的争用。 HPET计时器性能较差的原因是会将所有对时间戳的请求串行执行。 TSC计时器性能较好,因为有专用的寄存器来保存时间戳。缺点是可能不稳定,因为它是纯硬件的计时器,频率可变(与处理器的CLK信号有关)。

处理方法

如何解决这个问题? 最常见的办法是用单个调度线程来按毫秒更新时间戳,相当于维护一个全局缓存。

其他线程取时间戳时相当于从内存取,不会再造成时钟资源的争用,代价就是牺牲了一些精确度。

具体代码如下:

代码语言:javascript
复制
public class SystemClock {
  private static final SystemClock MILLIS_CLOCK = new SystemClock(1);
  private final long precision;
  private final AtomicLong now;

  private SystemClock(long precision) {
    this.precision = precision;
    now = new AtomicLong(System.currentTimeMillis());
    scheduleClockUpdating();
  }

  public static SystemClock millisClock() {
    return MILLIS_CLOCK;
  }

  private void scheduleClockUpdating() {
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
      Thread thread = new Thread(runnable, "system.clock");
      thread.setDaemon(true);
      return thread;
    });
    scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), precision, precision, TimeUnit.MILLISECONDS);
  }

  public long now() {
    return now.get();
  }
}

可以使用并发量大的情况下SystemClock.millisClock().now()输出当前时间,有一定精度上问题,得到是时间获取上效率。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 处理方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档