java - 使用 UUID 作为键时映射的线程安全
问题描述
有一个包含final
字段的服务。
@Service
public class RegularService {
private final DataMap map = new DataMap();
....
}
该final
字段的类DataMap
看起来像这样
class DataMap {
private Map<UUID, String> content1 = new HashMap<>();
private Map<UUID, String> content2 = new HashMap<>();
void updateContent(UUID id, String data) {
if (content1.containsKey(id)) {
....
return;
}
if (content2.containsKey(id)) {
content1.put(id, data);
content2.remove(id);
return;
}
content2.put(id, data);
}
问题是 - 是否updateContent
具有竞争条件?问题是,UUID
理论上使用意味着不同的线程永远不会访问相同的条目......
如果是,那么是否需要同步整个updateContent
方法或仅使用ConcurrentHashMap
就足够了?
解决方案
使用 UUID 作为键时映射的线程安全
映射的线程安全实际上与所讨论的关键对象无关。仅仅因为UUID.randomUUID()
返回一个唯一的 UUID 并不能以某种方式保证线程安全。问题在于内存同步以及线程如何查看和发布对映射的更改以及协调多个映射操作。
问题是 - 是否
updateContent()
具有竞争条件?
是的,它确实。首先,您不能在Map
不使用同步或并发Map
实现的情况下更新使用多个线程。 ConcurrentHashMap
将负责对映射的修改和线程之间内存的发布,以使它们保持同步。但是因为您要对需要协调的地图进行多项操作,所以您需要添加更多同步。
如果是,那么是否需要同步整个
updateContent()
方法或仅使用 ConcurrentHashMap 就足够了?
由于您要对 2 个地图进行多项更改,因此您需要使用synchronized
或以其他方式锁定多个操作。一旦你这样做了,就没有必要使用ConcurrentHashMap
. 您可以制作方法synchronized
,锁定其中一张地图,或制作特定final Object lockObject = new Object()
用于锁定操作。
例如,如果没有锁,则没有任何东西可以保护 thread1 看到content1
不包含 id XXX 的内容,然后content2
在 thread2 将其添加到之前继续检查content1
。所以thread1会覆盖thread2 data
,这不是你想要的。
推荐阅读
- vba - 另一个类'cBeam'的实例字典作为类'cNode'实例中的变量
- go - 如何关闭来自另一个 goroutine 的读取 TCP 连接?
- javascript - JavaScript - 计算两个日期之间的差异(年、日、小时或不到一小时)
- vuejs2 - 如何在 require() Vue 中绑定一个值
- python - 如何将额外的 URL 值传递给 Django 通用 DeleteView?
- terraform - 使用 Terraform 在 EMR 上为 Presto/Spark 启用粘合目录的选项
- c# - Azure Functions 2.x 不断抛出捕获的异常
- java - 是否有可能使这段代码更高效(java8,解析文件)?
- c++ - 如何正确显示特殊的中文、韩文、日文字符
- java - 如何使用扫描仪在给定多个输入的情况下获得多个输出