链接线程安全集合线程安全吗?

时间:2011-01-26 21:37:01

标签: java collections thread-safety

如果我有以下声明:

Map<String, Map<String, Person>> families = 
   Collections.synchronizedMap(new HashMap<String, Map<String, Person>>());

如果我然后链接一个这样的电话:

families.get(lastName).put(firstName, new Person());

这个线程安全吗?对我来说,看起来两个地图中只有一个是同步的,但如果不通过外部同步地图就无法到达内部地图,所以我不确定......

EDIT 到目前为止,两个答案都有优秀的分数!但现在我在想如果我这样做了:

families.put(lastName, Collections.synchronizedMap(new HashMap<String, Person>());

然后做了我的链接调用,是整个链线程安全吗?在get(lastName)put(firstName, new Person())之间,另一个线程可能获得内部地图吗?我想如果我想要整个链线程安全我需要将它放在一个synchronized块中,但我也想知道这是否也能正常工作......

3 个答案:

答案 0 :(得分:4)

你将通过同步的外部地图获得内部地图,但随后你可以用它做你想做的事情。所以线程安全。

如果你真的想在这个场景中使用线程安全,我会创建一个包含地图映射的对象,然后你可以通过同步访问器来控制访问。我建议这是一个很好的做法,适用于你撰写馆藏集合的大多数场景。

答案 1 :(得分:4)

内部地图线程安全。

如果某个其他线程

families.get(lastName).put(firstName, new Person());

使用相同的 lastName,然后一个线程可以获取内部地图,然后另一个线程获取内部地图,然后两个线程都调用put同一时间,打破一切。

使用synchronizedMap通常不足以实现正确的并发 - 通常您希望显式锁定每个事务,而不是围绕每个方法调用

答案 2 :(得分:1)

完全有可能在调用外部get()和内部put()之间,其他一些线程也调用外部get()并获得相同的内部映射。但由于它是同步的,所以无论如何都应该是安全的。

问题是当你把东西放到外部地图上时。线程如何确定是否有必要创建新的内部地图?假设你有这样的代码:

if (!families.containsKey(lastName)) {
  families.put(lastName, Collections.synchronizedMap(new HashMap<String, Person>());
}

现在,这肯定是不安全的,因为其他一些线程可能会同时执行相同的操作,因此您最终会创建两个内部映射,其中一个成为垃圾收集的候选者。

只需同步所有与整个结构一起使用的方法,并且不使用同步映射,这样会好得多。它可能会更快,因为您只需要一个级别的同步。