ConcurrentHashMap線程安全:分段鎖 到 synchronized + CAS

專欄系列文章地址:https://blog.csdn.net/qq_26437925/article/details/145290162

本文目標:

  1. 理解ConcurrentHashMap為什么線程安全;ConcurrentHashMap的具體細節還需要進一步研究

目錄

    • ConcurrentHashMap介紹
    • JDK7的分段鎖實現
    • JDK8的synchronized + CAS實現
      • put方法

ConcurrentHashMap介紹

百度AI介紹如下:
在這里插入圖片描述

JDK7的分段鎖實現

在 JDK7 中,ConcurrentHashMap 使用“分段鎖”機制實現線程安全,數據結構可以看成是”Segment數組+HashEntry數組+鏈表”,一個 ConcurrentHashMap 實例中包含若干個 Segment 實例組成的數組,每個 Segment 實例又包含由若干個桶,每個桶中都是由若干個 HashEntry 對象鏈接起來的鏈表。

Segment 類繼承 ReentrantLock 類,鎖的粒度為其中一個Segment,而不是整體。

在這里插入圖片描述

JDK8的synchronized + CAS實現

在這里插入圖片描述

每個桶可能是鏈表結構或者紅黑樹結構,鎖針對桶的頭節點加,鎖粒度小

put方法

定位Node數組位置使用CAS操作定位,真正進行插入操作的時候會使用synchronized關鍵字加鎖頭部

/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {// key, value 都不能為nullif (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;// 如果Node數組是空,則進行初始化;初始化是CAS操作if (tab == null || (n = tab.length) == 0)tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {// 數組位置節點為null,則CAS方式進行添加Node到數組位置if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))break;                   // no lock when adding to empty bin}else if ((fh = f.hash) == MOVED)// 如果數組位置節點正在遷移,則幫助遷移tab = helpTransfer(tab, f);else {// 沒有遷移,且數組位置不是空,則進行聊表或者紅黑樹的插入操作,可能涉及到鏈表轉紅黑樹V oldVal = null;// 直接用 synchronized 鎖住 鏈表或者紅黑樹的頭部synchronized (f) {if (tabAt(tab, i) == f) {// 鏈表遍歷判斷,替換老值,或者進行尾插if (fh >= 0) {binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key,value, null);break;}}}// 紅黑樹替換老值,或者進行紅黑樹插入else if (f instanceof TreeBin) {Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount);return null;
}

put完成后addCount(1L, binCount);會進行數量統計和擴容判斷操作,也是CAS操作

/*** Adds to count, and if table is too small and not already* resizing, initiates transfer. If already resizing, helps* perform transfer if work is available.  Rechecks occupancy* after a transfer to see if another resize is already needed* because resizings are lagging additions.** @param x the count to add* @param check if <0, don't check resize, if <= 1 only check if uncontended*/
private final void addCount(long x, int check) {CounterCell[] as; long b, s;if ((as = counterCells) != null ||!U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {CounterCell a; long v; int m;boolean uncontended = true;if (as == null || (m = as.length - 1) < 0 ||(a = as[ThreadLocalRandom.getProbe() & m]) == null ||!(uncontended =U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {fullAddCount(x, uncontended);return;}if (check <= 1)return;s = sumCount();}if (check >= 0) {Node<K,V>[] tab, nt; int n, sc;while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&(n = tab.length) < MAXIMUM_CAPACITY) {int rs = resizeStamp(n);if (sc < 0) {if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||transferIndex <= 0)break;if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))transfer(tab, nt);}else if (U.compareAndSwapInt(this, SIZECTL, sc,(rs << RESIZE_STAMP_SHIFT) + 2))transfer(tab, null);s = sumCount();}}
}

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

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

相關文章

Vue和Java使用AES加密傳輸

背景&#xff1a;Vue對參數進行加密&#xff0c;對響應進行解密。Java對參數進行解密&#xff0c;對響應進行解密。不攔截文件上傳類請求、GET請求。 【1】前端配置 安裝crypto npm install crypto-js編寫加解密工具類encrypt.js import CryptoJS from crypto-jsconst KEY …

開發板目錄 /usr/lib/fonts/ 中的字體文件 msyh.ttc 的介紹【微軟雅黑(Microsoft YaHei)】

本文是博文 https://blog.csdn.net/wenhao_ir/article/details/145433648 的延伸擴展。 本文是博文 https://blog.csdn.net/wenhao_ir/article/details/145433648 的延伸擴展。 問&#xff1a;運行 ls /usr/lib/fonts/ 發現有一個名叫 msyh.ttc 的字體文件&#xff0c;能介紹…

[ESP32:Vscode+PlatformIO]新建工程 常用配置與設置

2025-1-29 一、新建工程 選擇一個要創建工程文件夾的地方&#xff0c;在空白處鼠標右鍵選擇通過Code打開 打開Vscode&#xff0c;點擊platformIO圖標&#xff0c;選擇PIO Home下的open&#xff0c;最后點擊new project 按照下圖進行設置 第一個是工程文件夾的名稱 第二個是…

述評:如果抗拒特朗普的“普征關稅”

題 記 美國總統特朗普宣布對美國三大貿易夥伴——中國、墨西哥和加拿大&#xff0c;分別征收10%、25%的關稅。 他威脅說&#xff0c;如果這三個國家不解決他對非法移民和毒品走私的擔憂&#xff0c;他就要征收進口稅。 去年&#xff0c;中國、墨西哥和加拿大這三個國家&#…

九. Redis 持久化-AOF(詳細講解說明,一個配置一個說明分析,步步講解到位 2)

九. Redis 持久化-AOF(詳細講解說明&#xff0c;一個配置一個說明分析&#xff0c;步步講解到位 2) 文章目錄 九. Redis 持久化-AOF(詳細講解說明&#xff0c;一個配置一個說明分析&#xff0c;步步講解到位 2)1. Redis 持久化 AOF 概述2. AOF 持久化流程3. AOF 的配置4. AOF 啟…

C++11新特性之long long超長整形

1.介紹 long long 超長整形是C11標準新添加的&#xff0c;用于表示更大范圍整數的類型。 2.用法 占用空間&#xff1a;至少64位&#xff08;8個字節&#xff09;。 對于有符號long long 整形&#xff0c;后綴用“LL”或“II”標識。例如&#xff0c;“10LL”就表示有符號超長整…

瀏覽器查詢所有的存儲信息,以及清除的語法

要在瀏覽器的控制臺中查看所有的存儲&#xff08;例如 localStorage、sessionStorage 和 cookies&#xff09;&#xff0c;你可以使用瀏覽器開發者工具的 "Application" 標簽頁。以下是操作步驟&#xff1a; 1. 打開開發者工具 在 Chrome 或 Edge 瀏覽器中&#xf…

基于Springboot框架的學術期刊遴選服務-項目演示

項目介紹 本課程演示的是一款 基于Javaweb的水果超市管理系統&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 1.包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 2.帶你從零開始部署運行本套系統 3.該項目附…

新版231普通阿里滑塊 自動化和逆向實現 分析

聲明: 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向過程 補環境逆向 部分補環境 …

java-(Oracle)-Oracle,plsqldev,Sql語法,Oracle函數

卸載好注冊表,然后安裝11g 每次在執行orderby的時候相當于是做了全排序,思考全排序的效率 會比較耗費系統的資源,因此選擇在業務不太繁忙的時候進行 --給表添加注釋 comment on table emp is 雇員表 --給列添加注釋; comment on column emp.empno is 雇員工號;select empno,en…

泰山派Linux環境下自動燒錄腳本(EMMC 2+16G)

腳本名字&#xff1a; download.sh 輸入./download -h獲取幫助信息 &#xff0c;其中各個IMG/TXT燒錄的地址和路徑都在前幾行修改即可 #!/bin/bash# # DownLoad.sh 多鏡像燒錄腳本 # 版本&#xff1a;1.1 # 作者&#xff1a;zhangqi # 功能&#xff1a;通過參數選擇燒錄指定鏡…

正大杯攻略|分層抽樣+不等概率三階段抽樣

首先&#xff0c;先進行分層抽樣&#xff0c;確定主城區和郊區的比例 然后對主城區分別進行不等概率三階段抽樣 第一階段&#xff0c;使用PPS抽樣&#xff0c;確定行政區&#xff08;根據分層抽樣比例合理確定主城區和郊區行政區數量&#xff09; 第二階段&#xff0c;使用分…

開源智慧園區管理系統對比其他十種管理軟件的優勢與應用前景分析

內容概要 在當今數字化快速發展的時代&#xff0c;園區管理軟件的選擇顯得尤為重要。而開源智慧園區管理系統憑借其獨特的優勢&#xff0c;逐漸成為用戶的新寵。與傳統管理軟件相比&#xff0c;它不僅靈活性高&#xff0c;而且具有更強的可定制性&#xff0c;讓各類園區&#…

計算機網絡 應用層 筆記1(C/S模型,P2P模型,FTP協議)

應用層概述&#xff1a; 功能&#xff1a; 常見協議 應用層與其他層的關系 網絡應用模型 C/S模型&#xff1a; 優點 缺點 P2P模型&#xff1a; 優點 缺點 DNS系統&#xff1a; 基本功能 系統架構 域名空間&#xff1a; DNS 服務器 根服務器&#xff1a; 頂級域…

人類心智逆向工程:AGI的認知科學基礎

文章目錄 引言:為何需要逆向工程人類心智?一、逆向工程的定義與目標1.1 什么是逆向工程?1.2 AGI逆向工程的核心目標二、認知科學的四大支柱與AGI2.1 神經科學:大腦的硬件解剖2.2 心理學:心智的行為建模2.3 語言學:符號與意義的橋梁2.4 哲學:意識與自我模型的爭議三、逆向…

游戲引擎學習第86天

倉庫: https://gitee.com/mrxiao_com/2d_game_2 回顧 繼續之前的工作。 昨天已經讓地形系統基本運行起來&#xff0c;但目前仍然需要進一步完善&#xff0c;使其能夠生成更多的地塊。目前的情況是&#xff0c;僅僅有一個地塊位于中心區域&#xff0c;而真正需要的是讓地塊覆蓋…

Python在線編輯器

from flask import Flask, render_template, request, jsonify import sys from io import StringIO import contextlib import subprocess import importlib import threading import time import ast import reapp Flask(__name__)RESTRICTED_PACKAGES {tkinter: 抱歉&…

力扣動態規劃-20【算法學習day.114】

前言 ###我做這類文章一個重要的目的還是記錄自己的學習過程&#xff0c;我的解析也不會做的非常詳細&#xff0c;只會提供思路和一些關鍵點&#xff0c;力扣上的大佬們的題解質量是非常非常高滴&#xff01;&#xff01;&#xff01; 習題 1.網格中的最小路徑代價 題目鏈接…

關于算盡圓周率

總有人提到圓周率算盡的問題&#xff0c;其實代碼都已經在前面給出了&#xff0c;自己跑一下就明白了。 用語言描述的話&#xff0c;那就是&#xff1a; 前面幾篇文章已經寫清楚了&#xff0c;圓周率的本質就是無限分辨率前提下的可二分度量單位。 就像是自然對數底&#xf…

從通訊工具到 AI 助理,AI手機如何發展?

隨著AI進軍各行各業&#xff0c;全面AI化時代已經到來。手機&#xff0c;作為現代人類的“數字器官”之一&#xff0c;更是首當其沖地融入了這一變革浪潮之中。 2024年年初&#xff0c;OPPO聯合IDC發布了《AI手機白皮書》&#xff0c;公布OPPO已邁向AI手機這一全新階段。到如今…