加载静态缓存的最佳模式或方法是什么?

use*_*270 3 java static

假设我有以下内容(假设仅限于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方法.它不会继续并再次加载缓存吗?

sjl*_*lee 6

在这种情况下加载缓存的最佳方法是利用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)

缓存将在第一次使用类时加载,并且由于静态初始化是线程安全的,因此将安全地填充映射.任何后续调用来检索值都可以在不涉及任何锁定的情况下完成.

尽可能利用静态初始化始终是个好主意.它安全,高效,而且通常非常简单.