techiall / Blog

🍋 [My Blog] See discussions
https://github.com/techiall/Blog/discussions
MIT License
8 stars 1 forks source link

Instant.now() 在 jdk1.8 和 jdk11 的区别 #73

Open techiall opened 4 years ago

techiall commented 4 years ago

使用 jdk1.8 和 jdk11 编译下面这段代码,发现输出结果不一样。

import java.time.Instant;

/**
 * @author techial
 */
public class Main {
    public static void main(String[] args) {
        System.out.println(Instant.now());
    }
}

两个 jdk 版本输出的结果如下:

$ java -version
openjdk version "11.0.7" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.7+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.7+10, mixed mode)

$ javac Main.java
$ java Main
2020-06-11T13:17:59.711337Z

$ java -version
java version "1.8.0_212"
Java(TM) SE Runtime Environment (build 1.8.0_212-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode)

$ javac Main.java
$ java Main      
2020-06-11T13:18:19.622Z

发现 jdk11 输出的精度变高了,Instant.now() 的实现是调用了 Clock.systemUTC().instant();,再点击 systemUTC() 方法,会发现 jdk11 和 jdk1.8 的实现逻辑不一样。

    /**
     * Obtains the current instant from the system clock.
     * <p>
     * This will query the {@link Clock#systemUTC() system UTC clock} to
     * obtain the current instant.
     * <p>
     * Using this method will prevent the ability to use an alternate time-source for
     * testing because the clock is effectively hard-coded.
     *
     * @return the current instant using the system clock, not null
     */
    public static Instant now() {
        return Clock.systemUTC().instant();
    }

jdk1.8 实现如下,只粘贴相关代码段。

    public static Clock systemUTC() {
        return new SystemClock(ZoneOffset.UTC);
    }

    static final class SystemClock extends Clock implements Serializable {
        private static final long serialVersionUID = 6740630888130243051L;
        private final ZoneId zone;

        SystemClock(ZoneId zone) {
            this.zone = zone;
        }
    ...

jdk11 实现如下,只粘贴相关代码段。

    public static Clock systemUTC() {
        return SystemClock.UTC;
    }

    static final class SystemClock extends Clock implements Serializable {
        private static final long serialVersionUID = 6740630888130243051L;
        private static final long OFFSET_SEED =
                System.currentTimeMillis()/1000 - 1024; // initial offest
        static final SystemClock UTC = new SystemClock(ZoneOffset.UTC);

        private final ZoneId zone;
        // We don't actually need a volatile here.
        // We don't care if offset is set or read concurrently by multiple
        // threads - we just need a value which is 'recent enough' - in other
        // words something that has been updated at least once in the last
        // 2^32 secs (~136 years). And even if we by chance see an invalid
        // offset, the worst that can happen is that we will get a -1 value
        // from getNanoTimeAdjustment, forcing us to update the offset
        // once again.
        private transient long offset;

        SystemClock(ZoneId zone) {
            this.zone = zone;
            this.offset = OFFSET_SEED;
        }

后来去网上查了一下,发现从 jdk9 开始后,提高了 java.time.Clock.systemUTC() 这个方法的精度。

Instant.now() 精度由毫秒提升到了微秒。

https://bugs.openjdk.java.net/browse/JDK-8068730