理解java的同步集合

时间:2018-03-26 10:59:04

标签: java collections java.util.concurrent

我正在阅读有关包装器实现的java官方doc,这是用于获取同步集合的集合中的静态方法,例如:List<Type> list = Collections.synchronizedList(new ArrayList<Type>()); ... 我不明白的是以下内容(我引用了java doc):

  

以这种方式创建的集合每个位都是线程安全的,作为正常同步的集合,例如Vector。   面对并发访问,用户在迭代时对返回的集合进行手动同步势在必行。原因是迭代是通过对集合的多次调用来完成的,集合必须组成一个原子操作......

如何作为线程安全的每一位在迭代时需要手动同步

2 个答案:

答案 0 :(得分:2)

在某种意义上它是线程安全的,它的每个方法都是线程安全的,但是如果你对集合执行复合操作,那么你的代码就有可能出现并发问题。

例如:

List<String> synchronizedList = Collections.synchronizedList(someList);
synchronizedList.add(whatever); // this is thread safe

单个方法add()是线程安全的,但如果我执行以下操作:

List<String> synchronizedList = Collections.synchronizedList(someList);
if(!synchronizedList.contains(whatever))
       synchronizedList.add(whatever); // this is not thread safe

if-then-add操作不是线程安全的,因为在whatever检查后,某些其他线程可能已将contains()添加到列表中。

答案 1 :(得分:1)

这里没有矛盾:从synchronizedXyz返回的集合会遇到与直接可用的同步集合相同的缺点,即需要在迭代集合时手动同步。

外部迭代的问题无法通过更好的类设计来解决,因为迭代集合本身就需要对其方法进行多次调用(see this Q&A for detailed explanation)。

请注意,从Java 1.8开始,您可以使用同步集合 * forEach方法进行迭代而无需其他同步。这是线程安全的,并带来额外的好处; see this Q&A for details

这与外部迭代不同的原因是集合中的forEach实现负责为您同步迭代。