| 方式 | 代碼示例 | 本質 | 推薦度 |
|---|---|---|---|
| 索引 for 循環 | for(int i=0;i | 隨機訪問 | ❌ 差(LinkedList O(n²)) |
| Iterator 顯式 | Iterator it=list.iterator(); while(it.hasNext()) it.next() | 迭代器模式 | ✅ 基礎 |
| 增強 for | for(Object item:list) | Iterator 語法糖 | ✅ 推薦 |
| forEach 匿名類 | list.forEach(new Consumer(){...}) | 內部迭代 | ✅ 函數式 |
| forEach Lambda | list.forEach(item -> ...) | Lambda 語法糖 | ⭐ 首選 |
Listlist = new ArrayList<>(); list.add(0); list.add(1); list.add(2); list.add(3); list.add(4); // 線程1 遍歷 new Thread(() -> { for (int item : list) { System.out.println("遍歷: " + item); Thread.sleep(1000); } }).start(); // 線程2 刪除 new Thread(() -> { Thread.sleep(1000); list.remove(4); System.out.println("list.remove(4)"); }).start();
輸出:
遍歷: 0 遍歷: 1 list.remove(4) Exception in thread "Thread-0" java.util.ConcurrentModificationException
原因:ArrayList 迭代器檢測 modCount 變化,拋出 ConcurrentModificationException(快速失敗機制)。
Vector 方法級 synchronized 保護單操作,但無法鎖定整個遍歷過程。直接遍歷同樣拋出 ConcurrentModificationException。
// 線程1
synchronized (list) {
for (int item : list) { ... }
}
// 線程2
list.remove(4); // Vector.remove 內部 synchronized,會等待鎖釋放
輸出:遍歷完成後才執行 remove,安全但鎖住整個列表,並發度極低。
volatile 切換引用。Listlist = new CopyOnWriteArrayList<>(); // ... 初始化 0-4 // 線程1 遍歷 new Thread(() -> { for (int item : list) { ... } }).start(); // 線程2 刪除 new Thread(() -> { Thread.sleep(1000); list.remove(4); System.out.println("list.remove(4)"); }).start();
輸出:
遍歷: 0 遍歷: 1 list.remove(4) 遍歷: 2 遍歷: 3 遍歷: 4
遍歷仍見到已刪除元素 4,因遍歷的是舊數組快照。最終一致性,適合「讀多寫少」場景。
public synchronized void forEach(Consumer super E> action) { ... }
方法級 synchronized 鎖定整個遍歷過程,線程安全遍歷。
Listlist = new Vector<>(); // ... 初始化 new Thread(() -> { list.forEach(item -> { ... }); // 內部加鎖 }).start(); new Thread(() -> { Thread.sleep(1000); list.remove(4); }).start();
輸出:遍歷全部完成後執行 remove,安全且代碼簡潔。
| 場景 | 推薦方案 | 優點 | 缺點 |
|---|---|---|---|
| 讀多寫少、容忍弱一致性 | CopyOnWriteArrayList | 無鎖讀、高並發讀性能 | 寫入複製數組開銷大、內存佔用高 |
| 寫入頻繁、需強一致性 | Vector + 手動 synchronized / Collections.synchronizedList | 強一致、標準 API | 遍歷期間鎖住整表、並發度低 |
| JDK 8+、函數式風格、需安全遍歷 | Vector.forEach / CopyOnWriteArrayList.forEach | 代碼簡潔、內部鎖控制 | Vector.forEach 仍鎖全表 |
| 高性能並發寫入 | 避免 List,改用 ConcurrentHashMap 或 隊列 | 分段鎖/CAS 高吞吐 | 語義不同,需重新設計 |
forEach Lambda 或增強 for。CopyOnWriteArrayList(接受遍歷見舊數據)。Vector.forEach 或手動 synchronized(list) 包裹遍歷。