--- old/src/java.base/share/classes/java/util/SimpleTimeZone.java 2017-11-24 23:34:23.807908209 +0100 +++ new/src/java.base/share/classes/java/util/SimpleTimeZone.java 2017-11-24 23:34:23.681910373 +0100 @@ -548,12 +548,11 @@ computeOffset: if (useDaylight) { - synchronized (this) { - if (cacheStart != 0) { - if (date >= cacheStart && date < cacheEnd) { - offset += dstSavings; - break computeOffset; - } + Cache cache = this.cache; + if (cache != null) { + if (date >= cache.start && date < cache.end) { + offset += dstSavings; + break computeOffset; } } BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ? @@ -671,14 +670,13 @@ } private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) { - synchronized (this) { - if (cacheStart != 0) { - if (time >= cacheStart && time < cacheEnd) { - return rawOffset + dstSavings; - } - if (year == cacheYear) { - return rawOffset; - } + Cache cache = this.cache; + if (cache != null) { + if (time >= cache.start && time < cache.end) { + return rawOffset + dstSavings; + } + if (year == cache.year) { + return rawOffset; } } @@ -689,11 +687,7 @@ if (time >= start && time < end) { offset += dstSavings; } - synchronized (this) { - cacheYear = year; - cacheStart = start; - cacheEnd = end; - } + this.cache = new Cache(year, start, end); } else { if (time < end) { // TODO: support Gregorian cutover. The previous year @@ -711,12 +705,7 @@ } } if (start <= end) { - synchronized (this) { - // The start and end transitions are in multiple years. - cacheYear = (long) startYear - 1; - cacheStart = start; - cacheEnd = end; - } + this.cache = new Cache((long) startYear - 1, start, end); } } return offset; @@ -876,7 +865,7 @@ * Generates the hash code for the SimpleDateFormat object. * @return the hash code for this object */ - public synchronized int hashCode() + public int hashCode() { return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset; @@ -1201,19 +1190,27 @@ /** * Cache values representing a single period of daylight saving - * time. When the cache values are valid, cacheStart is the start - * time (inclusive) of daylight saving time and cacheEnd is the - * end time (exclusive). + * time. Cache.start is the start time (inclusive) of daylight + * saving time and Cache.end is the end time (exclusive). * - * cacheYear has a year value if both cacheStart and cacheEnd are - * in the same year. cacheYear is set to startYear - 1 if - * cacheStart and cacheEnd are in different years. cacheStart is 0 - * if the cache values are void. cacheYear is a long to support - * Integer.MIN_VALUE - 1 (JCK requirement). - */ - private transient long cacheYear; - private transient long cacheStart; - private transient long cacheEnd; + * Cache.year has a year value if both Cache.start and Cache.end are + * in the same year. Cache.year is set to startYear - 1 if + * Cache.start and Cache.end are in different years. + * Cache.year is a long to support Integer.MIN_VALUE - 1 (JCK requirement). + */ + private static final class Cache { + final long year; + final long start; + final long end; + + Cache(long year, long start, long end) { + this.year = year; + this.start = start; + this.end = end; + } + } + + private transient volatile Cache cache; /** * Constants specifying values of startMode and endMode. @@ -1282,9 +1279,8 @@ // Maximum number of rules. private static final int MAX_RULE_NUM = 6; - private synchronized void invalidateCache() { - cacheYear = startYear - 1; - cacheStart = cacheEnd = 0; + private void invalidateCache() { + cache = null; } //----------------------------------------------------------------------