java – 缓存JDK TimeZone实例

我们面临着重大的性能问题,TimeZone :: getTimeZone(String)是一个完整的瓶颈.它正在对类本身进行锁定(因为该方法是静态的),并且当前几乎所有执行线程都在等待获取此锁.

我提出了以下解决方案.它被证明是对性能的巨大推动.

private static final Object TIME_ZONE_CACHE_LOCK = new Object();
private static volatile Map<String, TimeZone> ourCachedTimeZones = new HashMap<>();

public static TimeZone getTimeZoneFor(String timeZoneId)
{
    TimeZone timeZone = ourCachedTimeZones.get(timeZoneId);

    if (timeZone == null)
    {
        TimeZone newTimeZone = TimeZone.getTimeZone(timeZoneId);

        synchronized (TIME_ZONE_CACHE_LOCK)
        {
            timeZone = ourCachedTimeZones.get(timeZoneId);

            if (timeZone == null)
            {
                timeZone = newTimeZone;
                Map<String, TimeZone> cachedTimeZones = new HashMap<>(ourCachedTimeZones);
                cachedTimeZones.put(timeZoneId, timeZone);
                ourCachedTimeZones = cachedTimeZones;
            }
        }
    }

    // Clone is needed since TimeZone is not thread-safe
    return (TimeZone) timeZone.clone();
}

我的问题:有没有人知道在TimeZone类之外缓存TimeZone实例是否安全?这意味着TimeZone / ZoneInfo / ZoneInfoFile会在内部更新其缓存,以便我在这里使用的应用程序缓存与TimeZone中的应用程序缓存不一致.

在有人建议之前 – 它不是升级到JDK 8日期/时间API的选项,也不是Joda时间.

在有人抱怨之前:-) – 我知道通常不建议使用复查成语.

最佳答案 一旦JVM从文件加载了TimeZones,它们就会被修复.

从Oracle检查Timezone Updater Utility:

http://www.oracle.com/technetwork/java/javase/tzupdater-readme-136440.html

您需要退回JVM才能应用更新.

请注意,缓存将是用于您的目的的缓存.其他一些库仍然可能(重新)使用慢速路径加载TimeZone.

但是这里有一个重要的警告:
你不会获得太多收益. HotSpot实现已经缓存:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/util/calendar/ZoneInfoFile.java/#125

调用堆栈是:

> ZoneInfoFile :: getZoneInfo0(String)
> ZoneInfoFile :: getZoneInfo(String)
> ZoneInfo :: getTimeZone(String)
> TimeZone :: getTimeZone(String)

因为返回的区域是可变的,所以它是防御性副本.

点赞