欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程環(huán)境下使用的集合類示例詳解

 更新時間:2023年07月22日 09:31:52   作者:韻秋梧桐  
這篇文章主要給大家介紹了關于Java多線程環(huán)境下使用的集合類的相關資料,開發(fā)過程中經(jīng)常遇到這種需求,文中通過代碼示例和圖文介紹的非常詳細,需要的朋友可以參考下

前言

Java標準庫中大部分集合類都是線程不安全的, 多線程環(huán)境下使用同一個集合類對象, 很可能會出問題; 只有少部分是線程安全的, 比如: Vector, Stack, HashTable這些, 關鍵方法都會帶有 synchronized, 但一般是不推薦使用這幾個類的.

一. 多線程環(huán)境下使用ArrayList

ArrayList在多線程中是線程不安全的, 使用時要保證線程安全的話有如下幾種方式:

  1. 涉及線程安全問題的代碼中, 自己使用synchronized或者ReentrantLock進行加鎖.
  2. 使用標準庫里面的操作: Collections.synchronizedList(new ArrayList); synchronizedList中的關鍵操作上都帶有synchronized的.
  3. 使用基于寫實拷貝實現(xiàn)的CopyOnWriteArrayList.

所謂寫實拷貝就是, 如果針對該ArrayList進行讀操作, 不會做任何額外的工作, 因為只有只有讀操作的話是不涉及線程安全問題的;

如果進行寫操作則拷貝一份新的ArrayList, 然后針對新的ArrayList進行修改, 如果在寫過程中有讀操作, 那么就去讀舊ArrayList, 當我們新的ArrayList寫操作完成之后, 就讓新的替換舊的ArrayList(本質上就是一個引用的賦值, 是原子的).

很明顯, 這里寫時拷貝的方案, 優(yōu)點是在讀多寫少的場景下, 性能很高, 不需要加鎖競爭; 缺點是這種方案占用內存較多, 要求這個ArrayList不能太大, 而且新寫的數(shù)據(jù)不能被第一時間讀取到.

??寫時拷貝的應用:

這種寫時拷貝的思路可以應用在服務器的 “熱加載” (reload) 這樣的功能上.

在服務器程序中, 包含有很多的子功能, 有的功能想要使用, 有的不想要使用, 有的希望功能應用不同, 所以可以使用一系列的 “開關選項” 來控制當前這個程序的工作狀態(tài), 這里就涉及到服務器程序配置文件的修改, 修改配置后可能就需要重啟服務器才能生效, 但是重啟操作可能成本比較高.

為什么說成本比較高呢?

假設一個服務器重啟需要花5min(往小了說的), 如果有20臺這樣的服務器, 總的重啟時間就得100min, 注意這20臺服務器是不能一起重啟的, 一起重啟就意味著在這5min中所有的服務器都不工作了, 服務就中斷了, 用戶發(fā)起的請求就沒有了任何的響應, 這個狀況就是比較嚴重的事故了.

而使用 “熱加載” 這樣功能就可以不重啟服務器實現(xiàn)配置的更新, 可以利用寫時拷貝的思路, 新的配置放到新的對象中, 加載過程中, 請求仍然基于舊配置進行工作, 當新的對象加載完畢, 就使用新對象替代舊對象(替換完成之后,舊的對象就可以釋放了).

二. 多線程環(huán)境使用隊列

多線程環(huán)境下通常使用的是阻塞隊列:

  • ArrayBlockingQueue 基于數(shù)組實現(xiàn)的阻塞隊列.
  • LinkedBlockingQueue 基于鏈表實現(xiàn)的阻塞隊列.
  • PriorityBlockingQueue 基于堆實現(xiàn)的帶優(yōu)先級的阻塞隊列.
  • TransferQueue 最多只包含一個元素的阻塞隊列.

三. 多線程環(huán)境下使用哈希表

HashMap本身是線程不安全的, 將HashMap中的重要方法使用synchornized加鎖后, 就得到了Hashtable類, Hashtable是線程安全的, 但相比于Hashtable更推薦使用的是ConcurrentHashMap.

那么下面就來分析一下, ConcurrentHashMap相較于Hashtable進行了哪些優(yōu)化.

??1. 最大的優(yōu)化: ConcurrentHashMap相較于Hashtable大大縮小了鎖沖突的概率, 將一把大鎖換為多把小鎖.

首先看線程不安全的HashMap, 假設表中如下圖, 這里元素1, 2是在同一個鏈表上, 如果線程A修改(增/刪/改)元素1, 線程B修改(增/刪/改)元素2, 這里是存在線程安全問題的, 1和2位置這是兩個相鄰的節(jié)點, 如果此時并發(fā)的插入/刪除, 就需要修改這兩節(jié)點next的指向, 所以這個情況要解決是需要加鎖的.

再來看如果線程A修改元素3, 線程B修改元素4, 這里是沒有線程安全問題的, 3和4位置的節(jié)點是位于兩個不同的鏈表中的, 這個情況就相當于多個線程并發(fā)去修改不同的變量, 是不存在線程安全問題的, 隨之這里也就是不需要加鎖了.

img

上面說到的HashMap是有線程安全問題的, 而針對上面的場景使用Hashtable是可以解決線程安全問題的, 但Hashtable中不太必要的是它是直接在方法上加synchronized, 等于是是給this加鎖, 這把大鎖就導致了我們只要操作哈希表上的任意元素, 都會加鎖, 也就都可能會發(fā)生鎖沖突.

img

但是實際上, 基于哈希表的結構特點, 有些元素在進行并發(fā)操作的時候, 是不會產(chǎn)生線程安全問題的, 也就沒必要去加鎖控制了, 就如上面分析過的3和4位置的元素.

這就是不推薦使用Hashtable的主要原因, 這里鎖沖突概率太大了, 就勢必會造成一些并發(fā)效率低下的問題.

img

ConcurrentHashMap的做法是每個鏈表有各自的鎖, 就不是像Hashtable一樣大家共用一個鎖了, 具體來說, 就是使用每個鏈表的頭結點, 作為鎖對象, 這樣只有并發(fā)操作同一個鏈表中的元素才會有鎖競爭, 大大降低了鎖沖突的概率, 相較于Hashtable并發(fā)效率上也會提升不少.

相較于Hashtable, 這里就是把鎖的粒度變小了, 不同線程操作1和2時, 是針對同一把鎖進行加鎖, 會產(chǎn)生鎖競爭, 保證了線程安全; 而不同線程操作3和4時, 是針對不同的鎖進行加鎖, 所以不會產(chǎn)生鎖競爭.

img

上圖中的情況, 是針對JDK1.8及其以后的情況, 而JDK1.8之前, ConcurrentHashMap使用的是 “分段鎖”, 分段鎖本質上也是縮小鎖的范圍從而降低鎖沖突的概率, 但是這種做法不夠徹底, 一方面鎖的粒度切分的還不夠細, 另一方面代碼實現(xiàn)也更繁瑣.

img

??2. ConcurrentHashMap做了一個激進的操作, 只針對寫操作加鎖, 而針對讀操作不加鎖, 這里讀和讀之間沒有沖突, 寫和寫之間有沖突, 而讀和寫之間也沒有沖突是為什么呢?

在很多場景下, 讀寫之間不加鎖控制,可能會讀到一個寫了一半的結果, 如果寫操作不是原子的, 此時讀就可能會讀到寫了一半的數(shù)據(jù), 相當于臟讀了, 而這里的寫操作使用了volatile來保證我們每次都是從內存讀取的結果并且寫操作加鎖保證了寫操作是原子的, 這樣就沒有上述說到的問題了.

??3. ConcurrentHashMap內部充分利用CAS特性, 來減少加鎖的操作, 比如通過CAS來維護size屬性(元素個數(shù)).

??4. 針對擴容操作, 采取了"化整為零"的策略.

HashMapHashtable中的擴容, 是直接創(chuàng)建一個空間更大新數(shù)組, 然后將舊的數(shù)組上的每個元素搬到新數(shù)組上(刪除節(jié)點+插入節(jié)點), 當我們某一次進行put時, 元素個數(shù)達到負載因子設定的值, 就會觸發(fā)擴容操作, 此時如果哈希表中的元素特別多, 擴容操作就會比較耗時, 也就是某次put比平時的put卡很多倍.

而在ConcurrentHashMap中采取擴容方式是每次只搬運─小部分元素, 具體來說就是, 擴容時創(chuàng)建一個新的數(shù)組, 舊的數(shù)組也會保留下來, 之后的每次put操作直接往新數(shù)組上添加, 同時搬運一部分舊的元素到新數(shù)組上, 當進行get操作時, 新舊數(shù)組都進行查詢, 當進行remove操作時, 元素在哪個數(shù)組上正常進行刪除操作即可, 這樣經(jīng)過一段時間之后, 當所有元素都搬運到了性數(shù)組上, 然后再釋放舊數(shù)組即可.

總結:

  • HashMap: 線程不安全, key 允許為 null.
  • Hashtable: 線程安全, 使用 synchronized 鎖 Hashtable 對象, 效率較低, key 不允許為 null.
  • ConcurrentHashMap: 線程安全, 使用 synchronized 鎖每個鏈表頭結點, 鎖沖突概率低, 充分利用 CAS 機制, 優(yōu)化了擴容方式, key 不允許為 null.

到此這篇關于Java多線程環(huán)境下使用的集合類的文章就介紹到這了,更多相關Java多線程使用集合類內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論