Collections.synchronizedList和synced


68
List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
    list.add("message");
}

这里真的需要块“ synchronized(list){}”吗?

Answers:


97

在示例中,您无需同步。但是,非常重要,在迭代列表时需要在列表周围进行同步(如Javadoc中所述):

当用户遍历返回列表时,必须手动对其进行同步:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());   
}

14
链接到上述声明:文档
Martin Andersson

1
带有这样的同步集合的常见用例是在多个线程中添加到列表中,但是仅在所有任务完成后才对其进行迭代。在这种情况下,我看不出有任何理由在迭代周围进行同步,因为它是从单个线程完成的。
Desty

3
只要您知道列表在迭代时不会更新,就不需要同步它。不过,我不知道我是否将该用例描述为“普通”。(我已经多次看到ConcurrentModificationException。)在您提到的用例中,是什么原因阻止了一个线程在另一个线程正在迭代时再次添加到列表中?以及其他线程完成更新列表后,迭代线程如何“知道”?
山姆·戈德堡

同样,对于Collections.synchornizedMap,需要使用
synced

如果列表未同步,则不会存在并发修改异常吗?
user9791370

28

这取决于synchronized块的确切内容:

  1. 如果该块在列表上执行单个原子操作(如您的示例中所示),synchronized则多余。

  2. 如果该块执行列表上的多个操作-和需要维持用于化合物操作的持续时间的锁定-则synchronized多余的。一个常见的例子是遍历列表。


21

Collections.synchronizedList add方法的基础代码是:

public void add(int index, E element) {
    synchronized (mutex) {list.add(index, element);}
}

因此,在您的示例中,不需要添加同步。


它使用的互斥锁的示例是什么?
anoopelias

4
互斥量是javadoc中记录的集合本身(此)。
assylias,2013年


7

阅读此Oracle文档

它说:“当用户遍历返回列表时,必须手动对其进行同步”


1
该文档听起来像是教条,而不是解释。这就是为什么我找到这个讨论的原因。
蜜蜂大师

1

就像其他人提到的一样,同步的集合是线程安全的,但是默认情况下,不能保证对这些集合的复合操作是线程安全的。

根据JCIP,常见的复合动作可以是

  • 迭代
  • 导航
  • 如果缺席
  • 然后检查

OP的同步代码块不是复合操作,因此无论是否添加它都没有区别。

让我们以JCIP中的示例为例,并对其进行一些修改,以阐明为什么有必要使用锁定来保护复合操作。

有两种方法可对listCollections.synchronizedList

public Object getLast(List<String> list){
    int lastIndex = list.size() - 1;
    return list.get(lastIndex);
}

public void deleteLast(List<String> list){
    int lastIndex = list.size() - 1;
    list.remove(lastIndex);
}

如果两个不同的线程同时调用方法getLastdeleteLast,则下面的交错可能会发生并getLast会抛出ArrayIndexOutOfBoundsException。假设电流lastIndex为10。

线程A(deleteLast)->删除
线程B(getLast)-------------------->获取

线程A在线程B中remove进行get操作之前的元素。因此,线程B仍使用10作为lastIndexto调用list.get方法,这将导致并发问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.