缓存JDK TimeZone实例

时间:2015-06-02 12:25:54

标签: java 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时间。

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

2 个答案:

答案 0 :(得分:2)

一旦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(字符串)
  • ZoneInfoFile :: getZoneInfo(字符串)
  • 区信息:: getTimeZone获取(字符串)
  • 时区:: getTimeZone获取(字符串)

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

答案 1 :(得分:0)

这应该有效。但是很少有建议:

  1. 您可以使用并发hashmap
  2. 或者你可以使用番石榴(https://code.google.com/p/guava-libraries/wiki/CachesExplained
  3. 我之前尝试过这个,并且我使用了1天的TTL作为缓存条目。每天缓存都会刷新(延迟加载)。