我们有一个 Spring Boot 服务,它只是提供来自地图的数据。地图会定期更新,由调度程序触发,这意味着我们构建一个新的中间地图,加载所有需要的数据,一旦完成,我们就会分配它。为了克服并发问题,我们引入了一个 ReentrantReadWriteLock,它在中间映射分配发生的那一刻打开一个写锁,当然在访问映射时打开一个读锁。请参阅下面的简化代码
@Service
public class MyService {
private final Lock readLock;
private final Lock writeLock;
private Map<String, SomeObject> myMap = new HashMap<>();
public MyService() {
final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
readLock = rwLock.readLock();
writeLock = rwLock.writeLock();
}
protected SomeObject getSomeObject(String key) {
readLock.lock();
try {
return this.myMap.get(key);
}
} finally {
readLock.unlock();
}
return null;
}
private void loadData() {
Map<String, SomeObject> intermediateMyMap = new HashMap<>();
// Now do some heavy processing till the new data is loaded to intermediateMyMap
//clear maps
writeLock.lock();
try {
myMap = intermediateMyMap;
} finally {
writeLock.unlock();
}
}
}
如果我们将服务设置为负载访问地图很多,我们仍然会在日志中看到 java.util.ConcurrentModificationException 发生,我不知道为什么。
BTW:同时我也看到了这个问题,这似乎也是一个解决方案。不过,我想知道我做错了什么,或者我是否误解了 ReentrantReadWriteLock 的概念
编辑:今天我得到了完整的堆栈跟踪。正如你们中的一些人所说,这个问题实际上与这段代码无关,它只是在重新加载发生的同时巧合发生。问题实际上在于对 getSomeObject() 的访问。在实际代码中, SomeObject 又是一个 Map ,并且每次访问这个内部 List 时都会对其进行排序(无论如何这都很糟糕,但这是另一个问题)。所以基本上我们遇到了这个问题