我们面临着重大的性能问题,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实现已经缓存:
调用堆栈是:
> ZoneInfoFile :: getZoneInfo0(String)
> ZoneInfoFile :: getZoneInfo(String)
> ZoneInfo :: getTimeZone(String)
> TimeZone :: getTimeZone(String)
因为返回的区域是可变的,所以它是防御性副本.