【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )
文章目錄
- I . Java 集合的線程安全概念 ( 加鎖同步 )
- II . 線程不安全集合 ( 沒有并發(fā)需求 推薦使用 )
- III . 集合屬性說明
- IV . 早期的線程安全集合 ( 不推薦使用 )
- V . 推薦使用的線程安全集合 ( 推薦使用 )
- VI . CopyOnWrite 機制
I . Java 集合的線程安全概念 ( 加鎖同步 )
1 . 線程安全問題引入 : 使用 Java 集合時 , 不可避免的要在多線程訪問集合 , 如果線程安全處理不當 , 就會造成不可預知的故障 ;
2 . 加鎖阻塞實現(xiàn)線程安全 : 當多線程操作 Java 集合時 , 使用 synchronized 關鍵字 加鎖阻塞任何對集合的操作 , 修改完畢后 , 解除阻塞 , 防止出現(xiàn)多線程操作 , 出現(xiàn)數(shù)據(jù)污染 ;
3 . 加鎖前后性能對比 : 如果將集合加鎖 , 顯然會降低程序的性能 , 普通集合 要比 線程安全集合 性能高 ;
4 . 線程安全與性能最佳實踐 :
① 線程不安全操作 ( 保證性能 ) : 如果不需要多線程操作集合 , 那么直接使用線程不安全集合即可 , 使性能達到最高 ;
② 線程安全操作 ( 保證正確性 ) : 盡量避免自己手動使用 synchronized 關鍵字加鎖 , synchronized 開銷很大 , 消耗性能 ; 推薦使用 JDK 中提供的 java.util.concurrent 包線程安全集合 ;
II . 線程不安全集合 ( 沒有并發(fā)需求 推薦使用 )
線程不安全的集合 : Java 中的最基礎的集合 , 如果沒有并發(fā)需求 , 推薦使用這些集合 , 其性能高 ; 這些類都定義在 java.utils 包下 ; 線程安全集合都定義在 java.util.concurrent 包下 ;
1 . List 集合 : ArrayList , LinkedList ; 有序元素集合 , 每個元素都有一個索引 ( 從 0 計數(shù) ) ;
① ArrayList : 底層數(shù)據(jù)結構是 數(shù)組 , 通過下標可快速查詢 , 查詢 修改 性能高 , 增加 刪除 性能低 ;
② LinkedList : 底層數(shù)據(jù)結構是 鏈表 , 查詢 修改 性能低 , 增加 刪除 性能高 ;
2 . Set 集合 : HashSet , TreeSet ; 不能包含重復元素 ; 注意 null 元素也算一個元素 , 只能有一個 ;
① HashSet : 底層數(shù)據(jù)結構是 哈希表 ; 元素無序 , 唯一 ; 元素類需要重寫 hashCode 和 equals 兩個方法 , 保證唯一性 ;
② TreeSet : 底層數(shù)據(jù)結構是 紅黑樹 ; 元素有序 , 唯一 ; 元素類需要重寫 hashCode 和 equals 兩個方法 , 保證唯一性 ; 使用排序機制 ( 自然排序 / 比較器排序 ) 保證有序性 ;
- 自然排序 : 元素類需要實現(xiàn) Compareable 接口 , 覆蓋 compareTo 方法 ; 兩個排序策略二選一即可 ;
- 比較器排序 : TreeSet 初始化時 , 設置 Comparator 比較器 ; Comparator 是接口 , 需重寫 compare 方法 ;
③ LinkedHashSet : 底層數(shù)據(jù)結構是 哈希表 和 鏈表 ; HashSet 派生類 , 其操作與 HashSet 一致 , 沒有定義額外的方法 ;
HashSet 與 TreeSet 二者對比 : HashSet 性能高于 TreeSet , 但是不能排序 ;
3 . Map 集合 : HashMap , LinkedHashMap , TreeMap ;
① HashMap : 鍵 ( Key ) 使用哈希表維護 , 注意元素存放順序 , 其中的 元素添加順序 并不是 數(shù)據(jù)存放順序 ;
② LinkedHashMap : HashMap 派生類 , Key 除了使用 哈希表 保證其唯一性之外 , 還使用 鏈表 保證了其 順序性 , 元素添加順序 ( 訪問順序 ) 就是 數(shù)據(jù)的存放順序 ;
③ TreeMap : Key 使用紅黑樹維護 , Key 需要使用排序機制 ( 自然排序 / 比較器排序 ) 保證有序性 ;
- 自然排序 : 元素類需要實現(xiàn) Compareable 接口 , 覆蓋 compareTo 方法 ; 兩個排序策略二選一即可 ;
- 比較器排序 : TreeSet 初始化時 , 設置 Comparator 比較器 ; Comparator 是接口 , 需重寫 compare 方法 ;
上述 Hash , Tree , LinkedHash 等都是針對鍵 ( Key ) 進行維護的 ; 即使用 哈希表 , 紅黑樹 , 鏈表哈希表維護鍵 ( Key ) ;
III . 集合屬性說明
1 . Hash : 使用哈希表實現(xiàn) , 如 HashSet , HashMap , 目的是為了保證其元素唯一性 ;
① 特點 : 元素唯一 ;
① 定制 : 需要保證唯一元素類需要重寫 hashCode 和 equals 兩個方法 ;
2 . Array : 使用數(shù)組實現(xiàn) , 如 ArrayList ;
① 特點 : 有序 , 下標訪問 ;
3 . Linked : 使用鏈表實現(xiàn) , 如 LinkedList , 其目的是為了保證有序性 ;
① 特點 : 有序 ;
4 . Tree : 使用紅黑樹實現(xiàn) , 如 TreeSet , TreeMap , 其目的是為了保證插入的元素自動排序 ;
① 特點 : 自動排序 ;
② 實現(xiàn) : 使用排序機制 ( 自然排序 / 比較器排序 ) 保證有序性 ;
- 自然排序 : 元素類需要實現(xiàn) Compareable 接口 , 覆蓋 compareTo 方法 ; 兩個排序策略二選一即可 ;
- 比較器排序 : TreeSet 初始化時 , 設置 Comparator 比較器 ; Comparator 是接口 , 需重寫 compare 方法 ;
IV . 早期的線程安全集合 ( 不推薦使用 )
下面講的 Vector , HashTable 集合雖然線程安全 , 但是性能很低 , 不推薦使用 ; 已經(jīng)棄用的類就不再詳細解析了 ;
1 . 線程安全 List 集合 :
① Vector ( 棄用 ) : 與 ArrayList 功能與實現(xiàn)基本相同 , 方法前使用 synchronize 關鍵字同步 ;
② Stack : 棧 結構 , 元素后進先出 , Vector 子類 , 是線程安全的 ;
2 . 線程安全 Map 集合 : HashTable ( 棄用 ) , 與 HashMap 功能相同 , 方法前使用 synchronize 關鍵字同步 ; HashTable 鍵值都不能為空 , 否則會報空指針異常 ;
V . 推薦使用的線程安全集合 ( 推薦使用 )
java.util.concurrent 包提供了一系列線程并發(fā)工具 , 如 并發(fā)鎖 , 執(zhí)行器 , 原子類 , 并發(fā)控制類 , 阻塞隊列 , 并發(fā)集合 , 這里我們先討論并發(fā)集合 , 其余在 Java 并發(fā) 中研究 ;
1 . 推薦使用的線程安全集合 : java.util.concurrent 包下的 線程安全集合 ;
① 實現(xiàn)原理 : 也是通過加鎖實現(xiàn)線程安全 , 但是其加鎖力度很細 , 如區(qū)分讀寫加鎖 , 分段加鎖 ;
② 優(yōu)勢 : 兼顧了性能與線程安全 , 在保證線程安全的前提下 , 最大限度提高性能 ;
③ 注意 : 這些線程安全集合性能低于普通集合 , 如果不需要多線程訪問 , 優(yōu)先使用普通集合 ;
2 . 與早期的線程安全集合對比 :
① 早期的線程安全集合 : 全部操作都加鎖 , 多線程訪問幾乎每個操作都會阻塞 , 性能很低 ;
② java.util.concurrent 包的線程安全集合 : 加鎖的力度很細 , 大部分的線程操作不會加鎖 , 沒有沖突 , 性能比早期線程略高 , 比現(xiàn)場不安全的線程低 ;
3 . concurrent 包的線程安全集合 : concurrent 包中提供了一系列線程安全的集合 , List , Map , Set , Queue 都有對應的線程安全容器 ;
① List 集合 : CopyOnWriteArrayList ;
② Set 集合 : CopyOnWriteArraySet , ConcurrentSkipListSet ;
③ Map 集合 : ConcurrentMap , ConcurrentHashMap , ConcurrentSkipListMap , ConcurrentNavigableMap ;
④ Queue 隊列 : ConcurrentLinkedQueue , ConcurrentLinkedDeque ;
VI . CopyOnWrite 機制
1 . 集合元素修改 ( 加鎖并復制 ) : 顧名思義就是在修改集合中的元素時 , 不直接操作當前的集合 , 而是先把集合拷貝一份 , 然后在新的集合中進行修改操作 , 最后將引用指向新的集合 ;
① 修改操作 : add , remove , clear , set 等操作都是加鎖 ;
② 本質(zhì) : 相當于每次修改都創(chuàng)建了一個新集合 ;
③ 寫入互斥 : 多個線程同時修改集合的數(shù)據(jù)是互斥的 ;
2 . 集合元素讀取 ( 不加鎖 ) : CopyOnWrite 集合的 get 方法不加鎖 , 因為其修改集合時不是修改當前的集合 , 當前集合不會出現(xiàn)數(shù)據(jù)污染 ;
① 同時讀取 : CopyOnWrite 集合支持多個線程同時讀取集合數(shù)據(jù) ;
3 . 缺陷 :
① 性能 : 每次修改集合 , 都要將整個集合復制一次 , 如何集合很大 , 并且修改頻繁 , 那么會導致性能很低 ;
② 實時性 : 讀取的時候 , 有可能線程正在被修改 , 讀取完畢后 , 有可能集合已經(jīng)更新了 , 當前讀取的數(shù)據(jù)已經(jīng)過時 , 不能保證數(shù)據(jù)的實時性 ;
4 . 適用場景 : CopyOnWrite 機制的集合適用于查詢多 , 修改少 , 數(shù)據(jù)量小的集合 ; 數(shù)據(jù)量過大 , 或修改頻繁 , 性能很低 ;
總結
以上是生活随笔為你收集整理的【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【设计模式】享元模式 实现 ( 实现流程
- 下一篇: 【数据挖掘】数据挖掘算法 组件化思想 (