在这种情况下,volatile hashmap 是否足够?

Is a volatile hashmap sufficient in this case?

我之前写了一段代码,它从 jar 文件动态加载 classes。 所以,基本上123-de目录可以有a.jar,456-fg目录可以有另一个a.jar。现在根据某些参数,我决定使用哪个 jar 并从 123-de 目录或 456-fg 目录加载 class 说 calc.java。

为此,我必须创建 classloader 并使用这些 classloader 来加载 calc.java

当然,每个 jar 应该有一个 class 加载程序,每个 class.

应该有一个加载到内存中的 class

为此,我使用了一个存储 class 加载器/ class 的并发哈希图。 说这个并发哈希图的键是目录名。

所以,给定一个目录,我检查 classloader 是否已经存在 - 如果不存在,我创建一个然后存储它。

if(classLoaderMap.get(directoryPath) == null){
        rlock.lock();
        try{
            if(classLoaderMap.get(directoryPath) == null){

                ClassLoader classLoader = // Create classLoader here.
                classLoaderMap.put(directoryPath, classLoader);
            }
        }finally{
            rlock.unlock();
        }
    }

此代码已经过测试并且工作正常。但是今天我重新访问这段代码并观察到我并不真正需要 concurrenthashmap 因为我正在使用显式锁定来写入它。我只需要内存可见性,因为我正在锁外读取它。所以,我真的在想 volatile hashmap 会完成这项工作吗?我应该还原它吗(尽管已经过测试,但不想这样做)还是保留它可以吗?

您是否正在其他地方访问 classLoaderMap 以从中读取值?如果是,您还需要在那里使用相同的锁以确保内存可见性。

volatile 在这种情况下无济于事,因为它只会确保对变量 classLoaderMapvalue 的更新对其他线程可见,不是地图本身的内容。

我仍然建议在这种情况下使用 ConcurrentHashMap,这样就不需要显式锁定并确保地图 内容 的内存可见性。

使用Java 8,使用ConcurrentHashMap时代码可以简化很多:

classLoaderMap.computeIfAbsent(directoryPath, (path) -> createClassLoader(path));

不,使用常规映射不安全,因为您需要锁定读取和写入。一种选择是使用 ReadWriteLock 这样您就可以支持非独占读取,而写入对读取和写入保持独占。另一种选择(可能是更好的选择)是坚持使用 ConcurrentHashMap 并摆脱锁定。至于如何原子更新的问题,直接使用原子computeIfAbsent()方法即可:

classLoaderMap.computeIfAbsent(directoryPath, p -> /* create class loader */);