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