我们面临着重大的性能问题,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时间。
在有人抱怨之前:-) - 我知道通常不建议使用复语成语。
答案 0 :(得分:2)
一旦JVM从文件加载了TimeZones,它们就会被修复。 从Oracle检查Timezone Updater Utility: http://www.oracle.com/technetwork/java/javase/tzupdater-readme-136440.html
您需要退回JVM才能应用更新。
请注意,缓存将是用于您的目的的缓存。其他一些库仍然可能(重新)使用慢速路径加载TimeZone。
但是这里有一个很大的警告: 你不会获得太多收益。 HotSpot实现已经缓存:
调用堆栈是:
因为返回的区域是可变的,所以它是防御性副本。
答案 1 :(得分:0)
这应该有效。但是很少有建议: