ConcurrentModificationException
?是 Java 中的一種異常,用于指示在迭代集合時,該集合的結構發生了并發修改。在 Java 中,許多集合類(如?
ArrayList
,?HashMap
?等)都不是線程安全的。如果一個線程在迭代集合的同時,另一個線程修改了該集合的結構(如添加、刪除元素),就可能導致?ConcurrentModificationException
?異常的拋出。這種異常通常在使用迭代器遍歷集合時發生,迭代器在創建時會記錄集合的結構狀態,如果在迭代期間發現集合結構已經發生了變化,就會拋出?
ConcurrentModificationException
。
CopyOnWriteArrayList
?和?Collections.synchronizedList都是 Java 中用于處理線程安全的列表操作的工具類,但它們在實現和適用場景上有一些區別。
CopyOnWriteArrayList
作用:
CopyOnWriteArrayList
?是一種適合讀操作遠多于寫操作的線程安全列表實現。- 寫操作(如添加、修改、刪除元素)會創建一個當前列表的副本,對副本進行操作,寫操作完成后將副本替換原來的列表。這保證了寫操作不會影響到正在進行的讀操作,從而避免了并發修改異常 (
ConcurrentModificationException
)。優點:
- 適合讀多寫少的場景,因為讀操作不需要加鎖,性能較高。
- 寫操作通過復制數組來實現線程安全,避免了使用顯式鎖帶來的性能損失。
缺點:
- 寫操作的性能相對較低,因為每次寫操作都要復制整個數組。
- 內存消耗較大,因為每次寫操作都會復制數組。
示例用法:
import java.util.concurrent.CopyOnWriteArrayList; import java.util.List;List<Integer> list = new CopyOnWriteArrayList<>(); list.add(1); list.add(2); list.add(3); // 在多線程環境中安全地進行讀寫操作 for (Integer num : list) {System.out.println(num);}// 注意:不建議在迭代過程中進行寫操作,因為迭代器不支持修改操作
Collections.synchronizedList
作用:
Collections.synchronizedList
?是通過包裝普通的?ArrayList
(或其他?List
?實現)來生成線程安全的列表。- 它使用了一個對象級的鎖(即在列表對象上加鎖),來確保多個線程不能同時修改列表,從而保證線程安全。
優點:
- 相對于?
CopyOnWriteArrayList
,它在寫操作時不需要復制整個數組,因此寫操作的性能可能會更好一些。- 使用簡單,通過靜態方法?
Collections.synchronizedList
?就可以獲取線程安全的列表。缺點:
- 在高并發環境下,由于使用了對象級的鎖,可能會造成性能瓶頸。
- 需要手動管理使用到的鎖,編寫代碼時需要確保在所有訪問列表的地方都正確地加鎖。
示例用法:
import java.util.Collections; import java.util.List; import java.util.ArrayList;List<Integer> list = Collections.synchronizedList(new ArrayList<>()); list.add(1); list.add(2); list.add(3); // 手動在多線程環境中通過 synchronized 同步塊或方法來安全地訪問 listsynchronized (list) {for (Integer num : list) {System.out.println(num);}}
區別比較
性能特征:
CopyOnWriteArrayList
?適合讀多寫少的場景,讀操作高效,寫操作較慢(讀操作訪問同一份列表,不加鎖)。Collections.synchronizedList
?在寫操作的性能上可能會優于?CopyOnWriteArrayList
,但在高并發情況下可能引入較大的性能開銷(讀寫操作都加上鎖)。內部實現:
CopyOnWriteArrayList
?寫操作通過復制數組來實現線程安全。Collections.synchronizedList
?使用 synchronized 關鍵字或者內部鎖來保證線程安全。使用方式:
CopyOnWriteArrayList
?直接使用構造函數或者?add
?等方法來操作列表,不需要額外的同步控制。Collections.synchronizedList
?需要在使用時通過 synchronized 關鍵字或者同步塊來手動管理線程安全。選擇合適的列表實現
- 讀多寫少:推薦使用?
CopyOnWriteArrayList
,因為它可以提供較高的讀取性能。- 讀寫操作均衡或者寫多讀少:考慮使用?
Collections.synchronizedList
?或其他更復雜的并發控制方式,根據具體情況選擇合適的同步策略。
總結來說,根據應用場景和性能要求選擇合適的線程安全列表實現,能夠有效地避免并發訪問帶來的問題。