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 /** |