List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
list.add("message");
}
块“synchronized(list){}”真的需要在这里吗?Collections.synchronizedList和同步
List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
list.add("message");
}
块“synchronized(list){}”真的需要在这里吗?Collections.synchronizedList和同步
底层代码Collections.synchronizedList添加方法是:
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
因此,在您例如,它不需要添加同步。
您不需要按照您的示例进行同步。然而,非常重要的,你需要的时候你迭代它(如在Javadoc注)周围列表同步:
当务之急是用户迭代它时,返回 名单上手动同步:
List list = Collections.synchronizedList(new ArrayList()); ... synchronized(list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
链接到上述语句:[docs](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList(java.util.List)) – 2013-02-13 09:28:05
常见用法像这样的一个同步集合的情况是添加到多个线程的列表中,但只在所有任务完成时才在最后进行迭代。 在这种情况下,我没有看到任何理由在迭代周围进行同步,因为它是从单个线程完成的。 – Desty 2013-08-06 12:30:43
只要您知道在迭代过程中列表未被更新,您就不需要同步它。不过,我不知道我是否会将该用例描述为“普通”。 (我曾经见过ConcurrentModificationException不止一次。)在你提到的用例中,当另一个线程正在迭代时,什么阻止线程再次添加到列表中?当其他线程完成更新列表时,迭代线程如何“知道”? – 2013-08-06 13:50:55
这取决于块的确切内容:
如果块执行在列表中是一个单一的原子操作(如你的例子),是多余的。
如果块执行列表上的多个操作 - 和需要保持的锁的化合物操作的持续时间 - 那么是不多余的。一个常见的例子是迭代列表。
同样重要的是要注意,任何使用迭代器(例如Collections.sort())的方法也需要封装在同步块中。
,排序方法已添加到List接口,并且此方法已在互斥锁上同步。 https://docs.oracle.com/javase/8/docs/api/java/util/List.html#sort-java.util.Comparator- – 2017-12-09 16:38:47
阅读本Oracle Doc
它说:“当务之急是用户迭代它时,返回的列表上手动同步”
这个文档听起来更像是一个教条而不是解释。这就是我找到这个讨论的原因。 – beemaster 2016-12-02 08:57:42
什么样的事情已被他人所提到的,同步的集合是thread-安全,但对这些集合的复合操作默认情况下不保证是线程安全的。
据JCIP,与普通复合动作可以
的OP的同步代码块不是复合动作,所以无论添加与否都没有区别。
我们以JCIP为例,对其进行一些修改,以阐明为什么有必要通过锁来保护复合动作。
有两种方法是在同一个集合list
操作,通过Collections.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);
}
包裹如果方法getLast
和deleteLast
是由两个不同的线程调用的同时,下面的交错可能发生,getLast
将抛出ArrayIndexOutOfBoundsException
。假定当前lastIndex
是10.
线程A(deleteLast) - >除去
线程B(getLast)-------------------->得到
线程A remove
线程B在get
操作之前的元素。因此,线程B仍然使用10作为lastIndex
来调用list.get
方法,这会导致并发问题。
它将使用什么样的互斥体? – anoopelias 2013-11-07 10:48:47
互斥量是javadoc中记录的集合本身(this)。 – assylias 2013-11-07 12:24:03