假设我有以下内容(假设仅限于 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;
}
}
在像 Web 应用程序服务器这样的高负载多线程环境中,如果 > 1 个线程试图同时获取和加载缓存,理论上这可能会出现问题。 (进一步假设 Web 应用程序上没有用于初始化缓存的启动代码)
仅使用 Collections.synchronizedMap 是否足以解决此问题?返回的 synchronizedMap 在执行 get() 时是否有性能问题,如果有很多线程正在访问它?
或者有一个非同步的 HashMap,而不是在加载方法或 boolean 变量上同步会更好吗?我认为,如果您同步其中任何一个,您最终可能会锁定该类。
例如,如果 load 方法是同步的,如果 2 个线程同时进入 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
}
}
缓存将在第一次使用该类时加载,并且由于静态初始化是线程安全的,因此映射将被安全地填充。任何后续检索值的调用都可以在不涉及任何锁定的情况下完成。
尽可能利用静态初始化总是一个好主意。它安全、高效,而且通常非常简单。
关于java - 加载静态缓存的最佳模式或方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1143995/