首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 並發進階:同步容器 vs 並發容器深度解析

     編輯:Java 綜合教學

同步容器:看似安全,實則暗藏隱患

創建方式

  • 早期:Vector、Hashtable 直接實例化
  • JDK 1.2+:Collections.synchronizedXxx() 靜態工廠方法包裝普通集合

核心缺陷:復合操作非原子

同步容器的每個單獨方法是線程安全的,但多方法組成的復合操作(如「先判斷大小再獲取最後元素」、「遍歷中修改」)並非原子,仍需外部加鎖。

實戰案例:Vector 索引越界

// 線程 A:獲取最後元素
public static Integer getLast(Vector list) {
    int lastIndex = list.size() - 1;  // ① 讀取大小
    if (lastIndex < 0) return null;
    return list.get(lastIndex);       // ② 獲取元素
}

// 線程 B:刪除並添加元素
public static void deleteAndAdd(Vector list) {
    int lastIndex = list.size() - 1;
    if (lastIndex < 0) return;
    list.remove(lastIndex);           // ③ 刪除導致大小變化
    list.add(3);
}

若 ① 執行後、② 執行前,線程 B 執行了 ③,導致容器縮小,② 時索引越界拋出 ArrayIndexOutOfBoundsException。

修正方案:客戶端加鎖

public static Integer getLast(Vector list) {
    synchronized (list) {  // 必須鎖住容器對象本身
        int lastIndex = list.size() - 1;
        if (lastIndex < 0) return null;
        return list.get(lastIndex);
    }
}

同理,for 循環遍歷時若其他線程修改容器,也會拋異常,需同步整個遍歷塊,但會嚴重降低並發性。

迭代器與快速失敗

同步容器迭代期間若被並發修改,拋出 ConcurrentModificationException(fail-fast)。解決途徑:

  1. 遍歷期間鎖住容器(並發性差、易死鎖)
  2. 克隆容器副本遍歷(CopyOnWriteArrayList),適合「讀多寫少」場景

注意:toString()、equals()、hashCode() 等隱式迭代操作同樣會觸發快速失敗。

並發容器:為高並發而生

同步容器「一把鎖鎖全局」嚴重限制吞吐量。JDK 5.0 引入並發容器,核心優勢:

  • 分段鎖/無鎖算法:大幅降低鎖競爭
  • 弱一致性迭代器:遍歷不拋 ConcurrentModificationException
  • 豐富原子操作 API:如 putIfAbsent、replace 等

重點剖析:ConcurrentHashMap

特性說明
分段鎖技術將哈希表數組分為多個段,每段獨立加鎖,理論上支持 N 個線程並發寫入(N=段數)
弱一致性迭代器迭代時反映「某個時間點」的狀態,不拋異常,允許並發修改
size()/isEmpty()返回近似值,因統計過程中容器可能在變化
原子複合操作putIfAbsent(k,v)、remove(k,v)、replace(k,old,new) 等

其他常用並發容器

  • CopyOnWriteArrayList/Set:寫時復制,遍歷極快,適合「讀多寫少、容忍短暫不一致」場景(如事件監聽器列表)
  • ConcurrentSkipListMap/Set:跳表實現,有序並發映射/集合
  • ConcurrentLinkedQueue:無鎖隊列,高吞吐生產消費

選型建議

場景推薦容器理由
高並發 Map 讀寫ConcurrentHashMap分段鎖 + 弱一致性迭代器,性能最優
頻繁遍歷、極少修改的 ListCopyOnWriteArrayList遍歷無鎖、無需同步,寫入代價大但頻率低
有序 Map 需並發ConcurrentSkipListMap跳表 O(log n) 操作,支持並發範圍查詢
簡單生產消費隊列ConcurrentLinkedQueue無鎖 CAS,吞吐極高

總結

同步容器是「防禦性同步」,並發容器是「進攻性優化」。理解復合操作原子性、迭代器弱一致性、鎖粒度對吞吐的影響,是駕馭 Java 並發集合的關鍵。實戰中:優先選並發容器,避免客戶端加鎖,拥抱弱一致性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved