< prev index next >

jdk/src/java.base/share/classes/java/time/Clock.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 59,74 **** --- 59,77 ---- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java.time; + import java.io.IOException; + import java.io.ObjectInputStream; import static java.time.LocalTime.NANOS_PER_MINUTE; import static java.time.LocalTime.NANOS_PER_SECOND; import java.io.Serializable; import java.util.Objects; import java.util.TimeZone; + import sun.misc.VM; /** * A clock providing access to the current instant, date and time using a time-zone. * <p> * Instances of this class are used to find the current instant, which can be
*** 444,457 **** --- 447,472 ---- * Implementation of a clock that always returns the latest time from * {@link System#currentTimeMillis()}. */ 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 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; } @Override public ZoneId getZone() { return zone; }
*** 462,476 **** } 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); --- 477,530 ---- } return new SystemClock(zone); } @Override public long millis() { + // System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset) + // use the same time source - System.currentTimeMillis() simply + // limits the resolution to milliseconds. + // So we take the faster path and call System.currentTimeMillis() + // directly - in order to avoid the performance penalty of + // VM.getNanoTimeAdjustment(offset) which is less efficient. return System.currentTimeMillis(); } @Override public Instant instant() { ! // Take a local copy of offset. offset can be updated concurrently ! // by other threads (even if we haven't made it volatile) so we will ! // work with a local copy. ! long localOffset = offset; ! long adjustment = VM.getNanoTimeAdjustment(localOffset); ! ! if (adjustment == -1) { ! // -1 is a sentinel value returned by VM.getNanoTimeAdjustment ! // when the offset it is given is too far off the current UTC ! // time. In principle, this should not happen unless the ! // JVM has run for more than ~136 years (not likely) or ! // someone is fiddling with the system time, or the offset is ! // by chance at 1ns in the future (very unlikely). ! // We can easily recover from all these conditions by bringing ! // back the offset in range and retry. ! ! // bring back the offset in range. We use -1024 to make ! // it more unlikely to hit the 1ns in the future condition. ! localOffset = System.currentTimeMillis()/1000 - 1024; ! ! // retry ! adjustment = VM.getNanoTimeAdjustment(localOffset); ! ! if (adjustment == -1) { ! // Should not happen: we just recomputed a new offset. ! // It should have fixed the issue. ! throw new InternalError("Offset " + localOffset + " is not in range"); ! } else { ! // OK - recovery succeeded. Update the offset for the ! // next call... ! offset = localOffset; ! } ! } ! return Instant.ofEpochSecond(localOffset, adjustment); } @Override public boolean equals(Object obj) { if (obj instanceof SystemClock) { return zone.equals(((SystemClock) obj).zone);
*** 483,492 **** --- 537,552 ---- } @Override public String toString() { return "SystemClock[" + zone + "]"; } + private void readObject(ObjectInputStream is) + throws IOException, ClassNotFoundException { + // ensure that offset is initialized + is.defaultReadObject(); + offset = OFFSET_SEED; + } } //----------------------------------------------------------------------- /** * Implementation of a clock that always returns the same instant.
< prev index next >