Java中的纳秒
- 前言
- JDK8获取纳秒的问题
- JDK9之后获取纳秒的问题
- 参考资料
前言
最近在使用InfluxDB保存系统的操作日志,如果在插入的时候不指定time字段,influxDB会默认设置time,但一般来说,数据经过多方周转如果采用默认的插入时间,对业务来说误差较高。我们的日志是发送给kafka,然后消费者订阅kafka消费数据再保存到influxDB,数据会有延迟。因此会在数据产生的时候写入time字段值,对时间的精度要求比较高,这样才能有效防止数据丢失。
Java中时间精度最高的应该是纳秒了,所以查询了下获取纳秒的一些方法。
JDK8获取纳秒的问题
JDK8中提供了丰富的时间的工具类,但是实际上JDK8中没有真正获取纳秒的方法,可查看这篇文章,https://stackoverflow.com/questions/1712205/current-time-in-microseconds-in-java,
Instant
类中可以获取纳秒的方法,本质上是获取的毫秒,后6位都是0。
Instant instant = Instant.now();
int tt = instant.getNano();
System.out.println(tt);
查看java.time.Clock
类的源码可发现,本质是获取当前的System.currentTimeMillis()
生成时间类的。
static final class SystemClock extends Clock implements Serializable {
private static final long serialVersionUID = 6740630888130243051L;
private final ZoneId zone;
SystemClock(ZoneId zone) {
this.zone = zone;
}
@Override
public ZoneId getZone() {
return zone;
}
@Override
public Clock withZone(ZoneId zone) {
if (zone.equals(this.zone)) {
return this;
}
return new SystemClock(zone);
}
@Override
public long millis() {
return System.currentTimeMillis();
}
@Override
public Instant instant() {
return Instant.ofEpochMilli(millis());
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SystemClock) {
return zone.equals(((SystemClock) obj).zone);
}
return false;
}
@Override
public int hashCode() {
return zone.hashCode() + 1;
}
@Override
public String toString() {
return "SystemClock[" + zone + "]";
}
}
Jdk还有一个方法System.nanoTime()
可以提供纳秒的精度测量的方法,一般可以用来计算2个方法之间的差值,不能直接转成时间戳。
long startTime = System.nanoTime();
long elapsedNanos = System.nanoTime() - startTime;
可以利用这个特性,初始化t1,获取差值从而获取纳秒。
t1=System.nanoTime(),
offset=System.currentTimeMillis()*1_000_000 - t1,
//获取当前的纳秒
currentNano=System.nanoTime() + offset
https://github.com/jenetics/jenetics/blob/master/jenetics/src/main/java/io/jenetics/util/NanoClock.java 就是利用这个方法实现的。
JDK9之后获取纳秒的问题
之前有提过这方面的缺陷,https://bugs.openjdk.java.net/browse/JDK-8068730,JDK9之后优化了获取纳秒的问题。
Instant instant = Instant.now();
int tt = instant.getNano();
System.out.println(tt);
java.time.Clock源码里,增加了VM.getNanoTimeAdjustment
方法获取纳秒。
public Instant instant() {
long localOffset = offset;
long adjustment = VM.getNanoTimeAdjustment(localOffset);
if (adjustment == -1) {
localOffset = System.currentTimeMillis()/1000 - 1024;
adjustment = VM.getNanoTimeAdjustment(localOffset);
if (adjustment == -1) {
throw new InternalError("Offset " + localOffset + " is not in range");
} else {
offset = localOffset;
}
}
return Instant.ofEpochSecond(localOffset, adjustment);
}
这时候如要获取纳秒的时间戳就简单了。
Instant instant = Instant.now();
int tt = instant.getNano();
long time = instant.toEpochMilli()/1000*1000_000_000 + tt;
System.out.println(time);
参考资料
- https://stackoverflow.com/questions/1712205/current-time-in-microseconds-in-java
- https://bugs.openjdk.java.net/browse/JDK-8068730
- https://github.com/jenetics/jenetics/blob/master/jenetics/src/main/java/io/jenetics/util/NanoClock.java
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)