对象引用的线程安全重置
Thread-safe resetting of an object's reference
someParameters hashmap 由一个线程每二十分钟左右从 .csv 文件加载一次,并由 setParameters 方法设置。
它经常被调用 getParameters 的多个线程读取:执行一个值到相应值的查找转换。
代码是否不安全和/或实现此目的的 "wrong" 方法(特别是在性能方面)?我知道 ConcurrentHashMap 但我试图更基本地了解并发性,而不是使用固有线程安全的 类。
我看到的一个潜在风险是对象引用 someParameters 可能会在另一个线程正在读取副本时被重置,因此另一个线程可能没有最新值(这会对我来说很重要)。
public class ConfigObject {
private static HashMap<String, String> someParameters = new HashMap<String, String>();
public HashMap<String, String> getParameters(){
return new HashMap<String, String>(someParameters);
//to some thread which will only ever iterate or get
}
public void setParameters(HashMap<String, String> newParameters){
//could be called by any thread at any time
someParameters = newParameters;
}
}
如果我对您的问题的理解正确,您需要一次 change/replace 许多参数(原子地)。不幸的是,ConcurrentHashMap
不支持原子批量 inserts/updates。
为此,您应该使用共享 ReadWriteLock
。与Collections.synchronized...
相比的优点是可以同时执行并发读取:如果readLock
是从某个线程获取的,那么从另一个线程调用的readLock().lock()
不会块。
ReadWriteLock lock = new ReadWriteLock();
// on write:
lock.writeLock().lock();
try {
// write/update operation,
// e. g. clear map and write new values
} finally {
lock.writeLock().unlock();
}
// on read:
lock.readLock().lock();
try {
// read operation
} finally {
lock.readLock().unlock();
}
这里有两个问题
- 可见性问题,因为
someParameters
更新后可能对其他线程不可见,将此标记 someParameters
修复为 volatile
。
- 另一个问题是由于在 get 方法中创建新的 HashMap 而导致的性能问题,要解决这个问题,请使用 Utility 方法
Collections.unmodifiableMap()
这只是包装原始映射并不允许使用 put/remove 方法。
someParameters hashmap 由一个线程每二十分钟左右从 .csv 文件加载一次,并由 setParameters 方法设置。
它经常被调用 getParameters 的多个线程读取:执行一个值到相应值的查找转换。
代码是否不安全和/或实现此目的的 "wrong" 方法(特别是在性能方面)?我知道 ConcurrentHashMap 但我试图更基本地了解并发性,而不是使用固有线程安全的 类。
我看到的一个潜在风险是对象引用 someParameters 可能会在另一个线程正在读取副本时被重置,因此另一个线程可能没有最新值(这会对我来说很重要)。
public class ConfigObject {
private static HashMap<String, String> someParameters = new HashMap<String, String>();
public HashMap<String, String> getParameters(){
return new HashMap<String, String>(someParameters);
//to some thread which will only ever iterate or get
}
public void setParameters(HashMap<String, String> newParameters){
//could be called by any thread at any time
someParameters = newParameters;
}
}
如果我对您的问题的理解正确,您需要一次 change/replace 许多参数(原子地)。不幸的是,ConcurrentHashMap
不支持原子批量 inserts/updates。
为此,您应该使用共享 ReadWriteLock
。与Collections.synchronized...
相比的优点是可以同时执行并发读取:如果readLock
是从某个线程获取的,那么从另一个线程调用的readLock().lock()
不会块。
ReadWriteLock lock = new ReadWriteLock();
// on write:
lock.writeLock().lock();
try {
// write/update operation,
// e. g. clear map and write new values
} finally {
lock.writeLock().unlock();
}
// on read:
lock.readLock().lock();
try {
// read operation
} finally {
lock.readLock().unlock();
}
这里有两个问题
- 可见性问题,因为
someParameters
更新后可能对其他线程不可见,将此标记someParameters
修复为volatile
。 - 另一个问题是由于在 get 方法中创建新的 HashMap 而导致的性能问题,要解决这个问题,请使用 Utility 方法
Collections.unmodifiableMap()
这只是包装原始映射并不允许使用 put/remove 方法。