在我的项目中,我构建了Jersey Web Service。此服务具有每分钟运行一次的计划任务,并填满(通过putIfAbsent函数(并发哈希映射(但在之前清除它(。此外,Web 服务具有返回映射 json 的终结点:
return gson.toJson(map, type)
通过 JAVA API 函数clear不是一个并发函数,gson.toJson 只使用 Map API 函数,所以我需要并发清除和 getMap/copyMap 函数。所以我想自己用并发函数来实现这些功能:
public class ExtendedConcurrentHashMap<K,V> extends ConcurrentHashMap<K,V> {
private final ConcurrentHashMap<K,V> map;
public ExtendedConcurrentHashMap(ConcurrentHashMap<K,V> map) {
this.map = map;
}
public void clear() {
ConcurrentHashMap.KeySetView<K,V> keySet = map.keySet(); //concurrent function
Iterator<K> iterator = keySet.iterator();
while(iterator.hasNext()) {
K keyToRemove = iterator.next();
map.compute(keyToRemove, (key,value) -> null); // concurrent function
}
}
public Map<K,V> getMap() {
Map<K,V> mapCopy = new HashMap<>();
map.forEach((key,value) -> mapCopy.put(key,value)); // concurrent function
return mapCopy;
}
}
这是正确的方法吗?我不想使用读/写锁或同步函数,因为从端点性能获取 json 对我的 Web 服务非常重要。
部分填充的地图不会打扰我。获得性能,而不是在读/写/更新期间出现异常对我来说是最重要的
ConcurrentHashMap
中Map.clear()
的实现是线程安全的。文档中的注释是指从不同线程查看时数据的一致性:
对于聚合操作,如
putAll
和clear
,并发检索可能只反映某些条目的插入或删除。
您的解决方案遇到了同样的问题,并且该方法无法工作,因为ConcurrentHashMap
中没有全局锁定(实际上,读取永不锁定(。
如果要原子地执行批量操作,则必须手动执行锁定。Collections.synchronizedMap()
提供了一个包装器,使这变得简单。包装器本身用作所有操作的锁,因此在其上同步允许执行多个操作,而不必担心其他线程会在工作完成之前执行更新或读取。