假设我有以下内容(假设仅限于java 1.4,因此没有泛型):
public class CacheManager {
static HashMap states;
static boolean statesLoaded;
public static String getState(String abbrev) {
if(!statesLoaded) {
loadStates();
}
return (String) states.get(abbrev);
}
private static void loadStates() {
//JDBC stuff to load the data
statesLoaded = true;
}
}
Run Code Online (Sandbox Code Playgroud)
在像Web应用程序服务器这样的高负载多线程环境中,如果> 1线程试图同时获取并加载缓存,理论上这可能会出现问题.(进一步假设Web应用程序上没有用于初始化缓存的启动代码)
只是使用Collections.synchronizedMap足以解决这个问题吗?如果很多线程正在访问它,那么在执行get()时返回的synchronizedMap是否存在性能问题?
或者更好的是拥有一个非同步的HashMap,而是在load方法或boolean变量上同步?我认为如果你同步其中任何一个,你可能会最终锁定该类.
例如,如果load方法已同步,那么如果两个线程同时进入getStates()方法,并且两者都看到statesLoaded为false.第一个获取方法的锁定,加载缓存并将statesLoaded设置为true.不幸的是,第二个线程已经评估了statesLoaded为false,并且一旦锁定空闲就进入load方法.它不会继续并再次加载缓存吗?
在这种情况下加载缓存的最佳方法是利用JVM静态初始化:
public class CacheManager {
private static final HashMap states = new HashMap();
public static String getState(String abbrev) {
return (String) states.get(abbrev);
}
static {
//JDBC stuff to load the data
}
}
Run Code Online (Sandbox Code Playgroud)
缓存将在第一次使用类时加载,并且由于静态初始化是线程安全的,因此将安全地填充映射.任何后续调用来检索值都可以在不涉及任何锁定的情况下完成.
尽可能利用静态初始化始终是个好主意.它安全,高效,而且通常非常简单.