【多線程】線程安全集合類,ConcurrentHashMap實現原理

文章目錄

  • 線程安全集合類
  • 解決方案
    • 多線程環境使用順序表
    • 多線程環境使用隊列
    • 多線程環境使用哈希表
      • ConcurrentHashMap
        • 1. 縮小鎖的粒度
        • 2. 充分使用 CAS
        • 3. 針對擴容操作

線程安全集合類

ArrayListQueueHsahMap… 都是線程不安全的

VectorStackHashtable 都是線程安全的(內置了 synchronized),實際上這幾個東西并不推薦使用

  • 因為這幾個都是無腦加 synchronized,無論如何都要加鎖,哪怕單線程也要加鎖,不科學。很有可能出現阻塞,可能會使程序效率大打折扣
  • 編譯器的“鎖消除”并不能 100%解決問題,只能把十拿九穩的地方進行優化,有些代碼是鎖消除機制摸不透的

解決方案

多線程環境使用順序表

  1. 自己加鎖

image.png

  • ArrayList 套了個殼。ArrayList 各種操作本身不帶鎖,通過上述套殼之后,得到了新的對象,新的對象里面的關鍵方法都是帶有鎖的

  1. 使用 CopyOnWriteArrayList

這里面主要用到了“寫實拷貝

  • 線程安全問題,在多個線程修改同一個數據的時候會觸發

image.png|482

  • 把順序表復制一份,修改新的順序表內容,然后修改引用的指向,這樣就不會有線程安全問題
    • “修改引用指向”這個操作是原子的,不需要加鎖

這種操作有很大的局限性

  1. 修改不能太頻繁(復制開銷很大)
  2. 順序表也不應該太大

一般在服務器加載配置文件的時候,就要把配置文件的內容解析出來,放到內存的數據結構中(順序表/哈希表…)

  • 服務器的修改頻率很低
  • 配置文件一般體積都不大(幾 kb)

多線程環境使用隊列

  1. 自己加鎖
  2. BlockingQueue(線程安全的)

多線程環境使用哈希表

HashMap 肯定不行,它是線程不安全的。更靠譜的是 Hashtable,其在一些關鍵方法上添加了 synchornized,但這個不好用

  • 他倆區別就是有無 synchornized

后來標準庫又引入了一個更好的解決方案:ConcurrentHashMap

ConcurrentHashMap

改進:

1. 縮小鎖的粒度

image.png|485

  • Hashtable 是直接在方法上使用 synchornized,相當于是對 this 加鎖,整個哈希表就只有這一把鎖,此時,嘗試修改兩個不同鏈表上的元素,都會觸發鎖沖突(Hashtable 底層實現是數組+鏈表)

  • 鎖的粒度很大,是一個全局鎖,同一時刻只能有一個線程訪問整個哈希表。

  • 仔細觀察就可以發現,如果修改兩個不同鏈表上的元素,不涉及到線程安全問題(修改不同變量)

    • 如果修改的是同一個鏈表上的元素,就可能涉及到線程安全問題
    • 比如這倆變量在鏈表上的位置是相鄰的,操作引用的時候,就可能涉及到操作同一個引用
  • 此時,針對同一個鏈表操作,再加鎖;針對不同鏈表操作,就不必加鎖了(不要產生鎖沖突)


ConcurrentHashMap 就是把鎖變小了,給每一個鏈表都發了一個鎖image.png

  • 弄出了這么多鎖,會付出更多空間的代價嗎?
    • 不會;Java 中,任何一個對象都可以直接作為鎖對象。本身哈希表中就得有數組,數組的元素都是已經存在的(每個鏈表的頭結點),此時,只要使用數組元素(鏈表頭結點)作為加鎖的對象即可

image.png|405

  • 每個鏈表就是構成桶的一個木板。所謂“鎖桶”,就是針對每個木板(每個鏈表)分別加鎖的

Java 1.7 及其之前,ConcurrentHashMap 是通過“分段鎖”來實現的

  • 給若干個鏈表分配一把鎖
  • 這種設定,不太合適,實現更復雜,效率也不夠高,還要引入額外的空間開銷(重新定義鎖)
    Java 8 開始,這里的設定就變成每個鏈表一把鎖了
2. 充分使用 CAS

充分使用 CAS 原子操作,減少了一些加鎖

  • 比如,針對哈希表元素個數的維護

synchornized 里面不是剛開始是偏向鎖或者輕量級鎖,速度很快嗎?

  • synchornized 有可能成為重量級鎖,并且是否升級了不可控
3. 針對擴容操作

擴容是一個重量操作

0.75 是負載因子默認的擴容閾值,不是負載因子本體

  • 負載因子是你算出來的數
  • 拿著實際的元素個數/數組長度(桶的個數)算出來的數值,這個值可能是 0.1,可能是 0.5 可能是 1,可能是 10
  • 然后我們拿著這個值和擴容閾值進行比較,看看是否需要擴容

負載因子:描述了每個桶上面平均有多少個元素

  • 此時桶上的鏈表的元素不應該太長,才能保證遍歷的時間復雜度為 O ( 1 ) O(1) O(1)

如果太長:

  1. 變成樹(長度不平均的情況)
  2. 擴容
    • 創建一個更大的數組,把舊的 Hash 表的元素都給搬運到(刪除/插入)到新的數組上
    • 如果 hash 表本身元素非常多,這里的擴容操作就會消耗很長時間
    • hash 表平時都很快,突然間某個操作就變慢了,過一會又快了(表現不穩定,壞事)
    • 我們無法控制何時觸發擴容,一旦觸發擴容,就會導致這次操作非常耗時(用戶直觀感受:卡頓)

HashMap 的擴容操作是一把梭哈,在某一次插入元素操作中,整體完成擴容(就會卡頓,耗時)

ConcurrentHashMap 的策略是“化整為零,螞蟻搬家

  • 每次只搬運一部分元素
  • 假設有 1kw 個元素,此時擴容的時候,每次插入/查找/刪除,都會搬運一部分元素(每次搬運 5k 個元素),一共花 2k 次搬完(花的時間更長,但是值得)
  • 確保每操作消耗的時間都不會很長,避免出現很卡的情況

在擴容過程中,同時存在兩份哈希表,一份是新的,一份是舊的

  • 插入操作:直接往新的上插入
  • 刪除操作:新的舊的都直接刪除
  • 查找操作:新的舊的都要查詢一下

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/74117.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/74117.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/74117.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

spring-tx筆記

編程式事務與聲明式事務的理解 補充:什么是事務? 事務是一個重要概念,尤其在數據庫管理系統中。事務是指一組操作。,這些操作要么全部成功執行,要么全部不執行,確保數據的一致性和完整性 編程式事務 編…

Android第四次面試(Java基礎篇)

一、Java 中的 DCL 單例模式 單例模式是設計模式中最常用的模式之一,其核心目標是確保一個類在程序中僅有一個實例,并提供全局訪問點。在 Java 中,實現單例模式需要兼顧線程安全和性能優化。DCL(Double-Checked Locking&#xff0…

Java-SpringBootWeb入門、Spring官方腳手架連接不上解決方法

一. Spring 官網:Spring | Home Spring發展到今天已經形成了一種開發生態圈,Spring提供了若干個子項目,每個項目用于完成特定的功能(Spring全家桶) Spring Boot可以幫助我們非常快速的構建應用程序、簡化開發、提高效率 。 二. Spring Boot入…

1.7 無窮小的比較

1.定義 2.性質 3.無窮小的比較 3.1等價無窮小的性質 3.2 常見等價無窮小

StarRocks 升級注意事項

前段時間升級了生產環境的 StarRocks,從 3.3.3 升級到了 3.3.9,期間還是踩了不少坑所以在這里記錄下。 因為我們的集群使用的是存算分離的版本,也是使用官方提供的 operator 部署在 kubernetes 里的,所以沒法按照官方的流程進入虛…

深入探究 JVM 堆的垃圾回收機制(一)— 判活

垃圾回收分為兩步:1)判定對象是否存活。2)將“消亡”的對象進行內存回收。 1 判定對象存活 可達性分析算法:通過一系列“GC Roots”對象作為起始節點集,從這些節點開始,根據引用關系向下搜索,…

國產開發板—米爾全志T113-i如何實現ARM+RISC-V+DSP協同計算?

近年來,隨著半導體產業的快速發展和技術的不斷迭代,物聯網設備種類繁多(如智能家居、工業傳感器),對算力、功耗、實時性要求差異大,單一架構無法滿足所有需求。因此米爾推出MYD-YT113i開發板(基…

Tomcat虛擬主機配置詳解:Centos環境下多域名部署(詳細教程!)

🏡作者主頁:點擊! Tomcat服務器📝專欄:點擊! 🐧Linux高級管理防護和群集專欄:點擊! ??創作時間:2025年3月18日14點14分 最近在折騰 Tomcat 的時候&…

鴻蒙開發工程師簡歷項目撰寫全攻略

一、項目結構的黃金法則 建議采用「41」結構: 項目背景(業務價值)技術架構(鴻蒙特性)核心實現(技術難點)個人貢獻(量化成果)附加價值(延伸影響) …

dfs刷題排列問題 + 子集問題 + 組和問題總結

文章目錄 一、排列問題全排列II題解代碼 優美的排列題解代碼 二、子集問題字母大小寫全排列題解代碼 找出所有子集的異或總和再求和題解代碼 三、組合問題電話號碼的字母組合題解代碼 括號生成題解代碼 組合題解代碼 目標和題解代碼 組合總和題解代碼 總結 一、排列問題 全排列…

【Linux】VMware17 安裝 Ubuntu24.04 虛擬機

目錄 安裝教程 一、下載 Ubuntu 桌面版iso映像 二、安裝 VMware 三、安裝 Ubuntu 桌面版 VMware 創建虛擬機 掛載 Ubuntu ISO 安裝 Ubuntu 系統 安裝教程 一、下載 Ubuntu 桌面版iso映像 鏈接來自 清華大學開源軟件鏡像站 ISO文件地址:ubuntu-24.04.2-des…

CVPR2025 | 對抗樣本智能安全方向論文匯總 | 持續更新中~

匯總結果來源:CVPR 2025 Accepted Papers 若文中出現的 論文鏈接 和 GitHub鏈接 點不開,則說明還未公布,在公布后筆者會及時添加. 若筆者未及時添加,歡迎讀者告知. 文章根據題目關鍵詞搜索,可能會有遺漏. 若筆者出現…

PostgreSQL_數據回退,數據庫導出、導入

目錄 前置: 1 數據回退 1.1 代碼 1.2 pgAdmin4 中查看 1)t_daily 2) t_stock_daily 2 數據庫導出、導入 前置: 本博文是一個系列。在本人“數據庫專欄”-》“PostgreSQL_”開頭的博文。 1 數據回退 上一節“PostgreSQL_數據下載并…

golang單機鎖實現

1、鎖的概念引入 首先,為什么需要鎖? 在并發編程中,多個線程或進程可能同時訪問和修改同一個共享資源(例如變量、數據結構、文件)等,若不引入合適的同步機制,會引發以下問題: 數據競…

【HarmonyOS Next】鴻蒙應用實現彈框DialogHub詳解

【HarmonyOS Next】鴻蒙應用實現彈框DialogHub詳解 一、前言 鴻蒙中實現彈框目前官方提供openCustomDialog和CustomDialog兩種模式。推薦前者,詳情見下圖和官網文檔鏈接: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V14/arkts-u…

機器學習算法實戰——天氣數據分析(主頁有源碼)

?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連 ? ?個人主頁歡迎您的訪問 ?期待您的三連? ? ??? 1. 引言 天氣數據分析是氣象學和數據科學交叉領域的一個重要研究方向。隨著大數據技術的發展,氣象數據的采集、存儲和分…

輸電線路專業英語詞匯

輸電線路transmission line 雙回路double circuit 導線conductor 地線ground (Earth)wire 雙回路耐張塔double-circuit tension towers 直線塔tangent tower 地質Geological 水文Hydrological 塔位坐標Coordinate of Tower Location 轉角塔angle tower 直…

炫酷的3D按鈕效果實現 - CSS3高級特性應用

炫酷的3D按鈕效果實現 - CSS3高級特性應用 這里寫目錄標題 炫酷的3D按鈕效果實現 - CSS3高級特性應用項目介紹核心技術實現1. 基礎結構設計2. 視覺效果實現2.1 背景漸變2.2 立體感營造 3. 交互動效設計3.1 懸停效果3.2 按壓效果 技術要點分析1. 深度層次感2. 動畫過渡3. 性能優…

解決python配置文件類configparser.ConfigParser,插入、讀取數據,自動轉為小寫的問題

配置類 [Section1] Key_AAA Value[Section2] AnotherKey Value默認情況下,ConfigParser會將ini配置文件中的KEY,轉為小寫。 重載后配置類: 繼承類從configparser.ConfigParser改為configparser.RawConfigParser重載方法optionxform&#…

微服務的網關配置

微服務的網關配置 1. 網關路由 1.1 網關 1.1.1 存在問題 單體架構時我們只需要完成一次用戶登錄、身份校驗,就可以在所有業務中獲取到用戶信息。而微服務拆分后,每個微服務都獨立部署,這就存在一些問題:每個微服務都需要編寫身…