jdk/src/java.base/share/classes/java/time/Clock.java
changeset 28765 8878e8455f2a
parent 25859 3317bb8137f4
child 29108 57b3b196d3a6
equal deleted inserted replaced
28764:cdd5e4c034de 28765:8878e8455f2a
     1 /*
     1 /*
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    61  */
    61  */
    62 package java.time;
    62 package java.time;
    63 
    63 
       
    64 import java.io.IOException;
       
    65 import java.io.ObjectInputStream;
    64 import static java.time.LocalTime.NANOS_PER_MINUTE;
    66 import static java.time.LocalTime.NANOS_PER_MINUTE;
    65 import static java.time.LocalTime.NANOS_PER_SECOND;
    67 import static java.time.LocalTime.NANOS_PER_SECOND;
    66 
    68 
    67 import java.io.Serializable;
    69 import java.io.Serializable;
    68 import java.util.Objects;
    70 import java.util.Objects;
    69 import java.util.TimeZone;
    71 import java.util.TimeZone;
       
    72 import sun.misc.VM;
    70 
    73 
    71 /**
    74 /**
    72  * A clock providing access to the current instant, date and time using a time-zone.
    75  * A clock providing access to the current instant, date and time using a time-zone.
    73  * <p>
    76  * <p>
    74  * Instances of this class are used to find the current instant, which can be
    77  * Instances of this class are used to find the current instant, which can be
   444      * Implementation of a clock that always returns the latest time from
   447      * Implementation of a clock that always returns the latest time from
   445      * {@link System#currentTimeMillis()}.
   448      * {@link System#currentTimeMillis()}.
   446      */
   449      */
   447     static final class SystemClock extends Clock implements Serializable {
   450     static final class SystemClock extends Clock implements Serializable {
   448         private static final long serialVersionUID = 6740630888130243051L;
   451         private static final long serialVersionUID = 6740630888130243051L;
       
   452         private static final long OFFSET_SEED =
       
   453                 System.currentTimeMillis()/1000 - 1024; // initial offest
   449         private final ZoneId zone;
   454         private final ZoneId zone;
       
   455         // We don't actually need a volatile here.
       
   456         // We don't care if offset is set or read concurrently by multiple
       
   457         // threads - we just need a value which is 'recent enough' - in other
       
   458         // words something that has been updated at least once in the last
       
   459         // 2^32 secs (~136 years). And even if we by chance see an invalid
       
   460         // offset, the worst that can happen is that we will get a -1 value
       
   461         // from getNanoTimeAdjustment, forcing us to update the offset
       
   462         // once again.
       
   463         private transient long offset;
   450 
   464 
   451         SystemClock(ZoneId zone) {
   465         SystemClock(ZoneId zone) {
   452             this.zone = zone;
   466             this.zone = zone;
       
   467             this.offset = OFFSET_SEED;
   453         }
   468         }
   454         @Override
   469         @Override
   455         public ZoneId getZone() {
   470         public ZoneId getZone() {
   456             return zone;
   471             return zone;
   457         }
   472         }
   462             }
   477             }
   463             return new SystemClock(zone);
   478             return new SystemClock(zone);
   464         }
   479         }
   465         @Override
   480         @Override
   466         public long millis() {
   481         public long millis() {
       
   482             // System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset)
       
   483             // use the same time source - System.currentTimeMillis() simply
       
   484             // limits the resolution to milliseconds.
       
   485             // So we take the faster path and call System.currentTimeMillis()
       
   486             // directly - in order to avoid the performance penalty of
       
   487             // VM.getNanoTimeAdjustment(offset) which is less efficient.
   467             return System.currentTimeMillis();
   488             return System.currentTimeMillis();
   468         }
   489         }
   469         @Override
   490         @Override
   470         public Instant instant() {
   491         public Instant instant() {
   471             return Instant.ofEpochMilli(millis());
   492             // Take a local copy of offset. offset can be updated concurrently
       
   493             // by other threads (even if we haven't made it volatile) so we will
       
   494             // work with a local copy.
       
   495             long localOffset = offset;
       
   496             long adjustment = VM.getNanoTimeAdjustment(localOffset);
       
   497 
       
   498             if (adjustment == -1) {
       
   499                 // -1 is a sentinel value returned by VM.getNanoTimeAdjustment
       
   500                 // when the offset it is given is too far off the current UTC
       
   501                 // time. In principle, this should not happen unless the
       
   502                 // JVM has run for more than ~136 years (not likely) or
       
   503                 // someone is fiddling with the system time, or the offset is
       
   504                 // by chance at 1ns in the future (very unlikely).
       
   505                 // We can easily recover from all these conditions by bringing
       
   506                 // back the offset in range and retry.
       
   507 
       
   508                 // bring back the offset in range. We use -1024 to make
       
   509                 // it more unlikely to hit the 1ns in the future condition.
       
   510                 localOffset = System.currentTimeMillis()/1000 - 1024;
       
   511 
       
   512                 // retry
       
   513                 adjustment = VM.getNanoTimeAdjustment(localOffset);
       
   514 
       
   515                 if (adjustment == -1) {
       
   516                     // Should not happen: we just recomputed a new offset.
       
   517                     // It should have fixed the issue.
       
   518                     throw new InternalError("Offset " + localOffset + " is not in range");
       
   519                 } else {
       
   520                     // OK - recovery succeeded. Update the offset for the
       
   521                     // next call...
       
   522                     offset = localOffset;
       
   523                 }
       
   524             }
       
   525             return Instant.ofEpochSecond(localOffset, adjustment);
   472         }
   526         }
   473         @Override
   527         @Override
   474         public boolean equals(Object obj) {
   528         public boolean equals(Object obj) {
   475             if (obj instanceof SystemClock) {
   529             if (obj instanceof SystemClock) {
   476                 return zone.equals(((SystemClock) obj).zone);
   530                 return zone.equals(((SystemClock) obj).zone);
   482             return zone.hashCode() + 1;
   536             return zone.hashCode() + 1;
   483         }
   537         }
   484         @Override
   538         @Override
   485         public String toString() {
   539         public String toString() {
   486             return "SystemClock[" + zone + "]";
   540             return "SystemClock[" + zone + "]";
       
   541         }
       
   542         private void readObject(ObjectInputStream is)
       
   543                 throws IOException, ClassNotFoundException {
       
   544             // ensure that offset is initialized
       
   545             is.defaultReadObject();
       
   546             offset = OFFSET_SEED;
   487         }
   547         }
   488     }
   548     }
   489 
   549 
   490     //-----------------------------------------------------------------------
   550     //-----------------------------------------------------------------------
   491     /**
   551     /**