缓存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从文件中加载了时区,它们就固定了。检查Oracle的时区更新工具:http://www.oracle.com/technetwork/java/javase/tzupdater自述- 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(字符串)
  • ZoneInfo:: getTimeZone(字符串)
  • 时区::getTimeZone(字符串)

因为返回的Zone是可变的,所以它是一个防御性复制。

应该可以。以下是一些建议:

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

相关内容

  • 没有找到相关文章

最新更新