我有一个包含两个带有一些数据的Hashmaps的类。我希望每晚在地图中更新/重新加载数据(使用Quartz作业),并希望在数据刷新过程中锁定所有其他线程的读取。
public class A {
private Map<String, Object> someMap1 = new ConcurrentHashMap<String, Object>();
private Map<String, Object> someMap2 = new ConcurrentHashMap<String, Object>();
public void reloadData() {
someMap1.clear();
someMap2.clear();
// read new data here and re-fill the maps
...
}
public Object getDataFromMap(String key) {
// do some logic here and return data from map
return someObj;
}
}
对于所有“读者”线程,getDataFromMap()方法应该是可访问的,而不会在数据刷新过程中发生任何阻塞。
另一方面,reloadData()方法应等待所有“读者”完成,然后阻止地图读取和重新加载数据。
reloadData()的'synchronized'修饰符不是解决方案,因为它阻止所有类和所有“读者”,如果它们在getDataFromMap()逻辑中正在进行中。
答案 0 :(得分:5)
在java中的并发包中使用Lock类。 它有ReenterantReadWriteLock。
答案 1 :(得分:5)
您的要求完全适合ReentrantReadWriteLock
private Map<String, Object> someMap1 = new ConcurrentHashMap<String, Object>();
private Map<String, Object> someMap2 = new ConcurrentHashMap<String, Object>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public Object getDataFromMap(String key) {
r.lock();
try {
// do some logic here and return data from map
return someObj;
} finally {
r.unlock();
}
}
public void reloadData() {
w.lock();
try {
someMap1.clear();
someMap2.clear();
// read new data here and re-fill the maps
} finally {
w.unlock();
}
}
答案 2 :(得分:1)
而不是那样做,怎么样:
public class A {
private volatile Map<String, Object> someMap1 = new HashMap<String, Object>();
private volatile Map<String, Object> someMap2 = new HashMap<String, Object>();
public void reloadData() {
Map<String, Object> newMap1 = new HashMap<String, Object>();
Map<String, Object> newMap2 = new HashMap<String, Object>();
// read new data here and fill the new maps
someMap1 = newMap1;
someMap2 = newMap2;
}
public Object getDataFromMap(String key) {
// do some logic here and return data from map
return someObj;
}
}
这样,在重新加载期间无需阻止读者。缺点是在重新加载期间,您将同时在内存中拥有旧的和新的映射副本,这将增加您的最大内存消耗。
我上面给出的实现也可能包含一个微妙的竞争条件,因为这两个地图没有原子更新,所以读者可以看到someMap2
的旧版本,但someMap1
的新版本。如果这是一个问题,可以通过多种方式轻松解决。