在这种情况下,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
在这种情况下无济于事,因为它只会确保对变量 classLoaderMap
的 value 的更新对其他线程可见,不是地图本身的内容。
我仍然建议在这种情况下使用 ConcurrentHashMap
,这样就不需要显式锁定并确保地图 内容 的内存可见性。
使用Java 8,使用ConcurrentHashMap
时代码可以简化很多:
classLoaderMap.computeIfAbsent(directoryPath, (path) -> createClassLoader(path));
不,使用常规映射不安全,因为您需要锁定读取和写入。一种选择是使用 ReadWriteLock
这样您就可以支持非独占读取,而写入对读取和写入保持独占。另一种选择(可能是更好的选择)是坚持使用 ConcurrentHashMap
并摆脱锁定。至于如何原子更新的问题,直接使用原子computeIfAbsent()
方法即可:
classLoaderMap.computeIfAbsent(directoryPath, p -> /* create class loader */);
我之前写了一段代码,它从 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
在这种情况下无济于事,因为它只会确保对变量 classLoaderMap
的 value 的更新对其他线程可见,不是地图本身的内容。
我仍然建议在这种情况下使用 ConcurrentHashMap
,这样就不需要显式锁定并确保地图 内容 的内存可见性。
使用Java 8,使用ConcurrentHashMap
时代码可以简化很多:
classLoaderMap.computeIfAbsent(directoryPath, (path) -> createClassLoader(path));
不,使用常规映射不安全,因为您需要锁定读取和写入。一种选择是使用 ReadWriteLock
这样您就可以支持非独占读取,而写入对读取和写入保持独占。另一种选择(可能是更好的选择)是坚持使用 ConcurrentHashMap
并摆脱锁定。至于如何原子更新的问题,直接使用原子computeIfAbsent()
方法即可:
classLoaderMap.computeIfAbsent(directoryPath, p -> /* create class loader */);