ConcurrentHashMap實現線程安全的底層原理

2020-12-17 Java章魚小弟

項目中經常會有多個線程要訪問同一個數據,此時比較常用的辦法是用synchronize加鎖,CAS去進行安全的累加,去實現多線程場景下的安全的更新一個數據的效果,HashMap是用的比較多,可能就是多個線程同時讀寫一個HashMap,HashMap是線程不安全的,如果對整個map去synchronized加鎖,類似下面這種偽代碼也沒那麼必要。

synchronized(map){

}

這時候JDK就退出了線程安全的ConcurrentHashMap,那它是怎麼實現線程安全的呢?

HashMap底層本身就是一個大數組,JDK1.8以前是將大數組分成多個數組,分段加鎖,一個數組一個鎖。比如大數組分成[數組1],[數組2],[數組3] -->每個數組都對應一個鎖。多個線程過來,線程1要put的位置是數組1的第3個index的位置,線程2要put的位置是數組2的第5個index的位置,這兩個線程在不同的數組裡面放數據本身不存在線程安全問題就不需要加鎖。

JDK1.8以後,做了一些優化和改進,優化了鎖的細粒度,還是一個大數組,對數組中每個元素進行CAS。

[一個大數組]數組裡對每個元素進行put操作,都是有一個不同的鎖,剛開始進行put的時候,如果兩個線程都是在數組的第3個index位置進行put,這個時候採取的是CAS的策略,同一個時間只有一個線程能成功執行這個CAS,就是說他剛開始先獲取一個數組的第3個index位置的值,如果為null然後執行CAS,線程1比較一下達到預期就是put進去我的這條數據,同一時間其他線程執行CAS都會失敗。

通過對數組裡每個元素執行CAS的策略,會有一個明顯的好處,就是如果很多線程對數組裡不同的元素執行put,大家是沒有關係的不存在線程安全問題。如果其他人CAS失敗了,其他人此時會發現說該位置已經給剛才其他的人put進去值了,這個時候就需要在這個位置基於連表+紅黑樹來進行處理,synchronized(數組[3]),加鎖,然後put進去自己的數據。

對JDK1.8之後ConcurrentHashMap的一點小總結,如果是對數組裡同一個位置的元素進行並發的操作,就需要加鎖串行化處理,如果是對數組不同位置進行操作,大家就可以並發的處理。

相關焦點

  • 高並發編程系列:ConcurrentHashMap的實現原理(JDK1.7和JDK1.8)
    HashMap、CurrentHashMap 的實現原理基本都是BAT面試必考內容,阿里P8架構師談:深入探討HashMap的底層結構、原理、擴容機制深入談過hashmap的實現原理以及在JDK 1.8的實現區別,今天主要談CurrentHashMap的實現原理,以及在JDK1.7和1.8的區別。
  • 來複習一波,HashMap底層實現原理解析
    那麼我們能不能把以上兩種結合一起使用,從而實現查詢效率高和插入刪除效率也高的數據結構呢?答案是可以滴,那就是哈希表可以滿足,接下來我們一起複習HashMap中的put()和get()方法實現原理。HashMap的put()和get()的實現1、map.put(k,v)實現原理第一步
  • Java面試高頻考點:HashMap的底層原理
    作為一個Java開發工程師,在面試的過程中,最高頻被問到的一個問題就是:「請簡述一下HashMap的實現原理」,在日常開發中,大多數程式設計師只會使用,對於其實現細節,卻不了解,殊不知這是較基礎卻也最重要的知識點。這篇文章將向大家詳細解釋hashmap的底層到底做了哪些事情。
  • Java多線程:由淺入深看synchronized的底層實現原理
    淺聊synchronized的使用MDove:說起synchronized的底層實現原來,咱們先看看synchronized的倆種加鎖方式:1、某個對象實例內此作用域內的synchronized鎖 ,可以防止多個線程同時訪問這個對象的
  • Java面試必問之Hashmap底層實現原理(JDK1.7)
    Hashmap底層實現原理(get\put\resize)Hashmap怎麼解決hash衝突?Hashmap是線程安全的嗎?構造方法首先看構造方法的源碼由以上源碼可知,Hashmap的初始容量默認是16, 底層存儲結構是數組(到這裡只能看出是數組, 其實還有鍊表,下邊看源碼解釋)。基本存儲單元是Entry,那Entry是什麼呢?我們接著看Entry相關源碼由Entry源碼可知,Entry是鍊表結構。
  • 多線程高頻題:讀寫鎖,Volatile,ScheduledExecutorService 和 ConcurrentHashMap
    Reading Materials:(1) https://howtodoinjava.com/core-java/multi-threading/best-practices-for-using-concurrenthashmap/(2) Java 關鍵字 volatile 的理解與正確使用下面的視頻是 xcode 的課程的試聽視頻
  • Java 並發編程:Synchronized 及其實現原理
    的原理,再回頭上面的問題就一目了然了。我們先通過反編譯下面的代碼來看看Synchronized是如何實現對代碼塊進行同步的:package com.paddx.test.concurrent;public class SynchronizedDemo { public void method() { synchronized (this) {
  • 教你用 Python 實現 HashMap 數據結構
    hashmap和hash算法究竟是什麼關係?hashmap有哪些參數,這些參數分別是做什麼用的?hashmap是線程安全的嗎?我們怎麼來維護hashmap的平衡呢?讓我們帶著疑問來看看hashmap的基本結構。
  • 並發組件CountDownLatch的底層原理
    有了基本的使用經驗後,下面我們逐步分析下它的源碼原理。,而不同的AQS實現的Sync組件是不一樣的。            throw new InterruptedException();        if (tryAcquireShared(arg) < 0)            doAcquireSharedInterruptibly(arg);    } 這個還是很熟悉,不就是ReentrantLock的加鎖代碼的底層原理麼
  • 阿里面試官:說一下JDK1.7 ConcurrentHashMap的實現原理
    HashMap是java編程中最常用的數據結構之一,由於HashMap非線程安全,因此不適用於並發訪問的場景。JDK1.5之前,通常使用HashTable作為HashMap的線程安全版本,HashTable對讀寫進行全局加鎖,在高並發情況下會造成嚴重的鎖競爭和等待,極大地降低了系統的吞吐量,ConcurrentHashMap應運而生。
  • 使用Lock鎖:java多線程安全問題解決方案之Lock鎖
    今天我們來學習一下Lock鎖,它是java 1.5之後出現的接口 java.util.concurrent.locks.Lock接口Lock實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作,就來釋放鎖和獲取鎖來說,在使用synchronized 方法的時候,我們並不知道什麼時候獲取到了鎖,什麼時候釋放了鎖,而Lock接口不一樣,他提供了專門的獲取鎖和釋放鎖的方法。
  • Java8線程池ThreadPoolExecutor底層原理及其源碼解析
    小侃一下日常開發中, 或許不會直接new線程或線程池, 但這些線程相關的基礎或思想是非常重要的, 參考林迪效應;就算沒有直接用到, 可能間接也用到了類似的思想或原理, 例如tomcat, jetty, 資料庫連接池, MQ;本文不會對線程的基礎知識進行介紹
  • 面試必問的 ConcurrentHashMap
    我們最終知道HashMap是線程不安全的,因此在老版本JDK中提供了HashTable來實現多線程級別的,改變之處重要有以下幾點。❝HashTable的put, get,remove等方法是通過synchronized來修飾保證其線程安全性的。HashTable是 不允許key跟value為null的。
  • 面試官:不使用synchronized和lock,如何實現一個線程安全的單例?
    稍微了解一點單例的朋友也都知道實現單例是要考慮並發問題的,一般情況下,我們都會使用synchronized來保證線程安全。那麼,如果有這樣一道面試題:不使用synchronized和lock,如何實現一個線程安全的單例?你該如何回答?C類應聘者:可以使用餓漢模式實現單例。
  • 詳解鎖原理,synchronized、volatile+cas底層實現
    當嘗試給資源加鎖卻被其他線程先鎖定時,不是阻塞等待而是循環再次加鎖在鎖常被短暫持有的場景下,線程阻塞掛起導致CPU上下文頻繁切換,這可用自旋鎖解決;但自旋期間它佔用CPU空轉,因此不適用長時間持有鎖的場景2 synchronized底層原理代碼使用synchronized加鎖,在編譯之後的字節碼是怎樣的呢
  • Java編寫線程安全類的7個技巧
    幾乎每個Java應用程式都會用到線程。例如,Tomcat是在單獨的工作線程中處理每個請求,胖客戶機(Fat Client)在專用工作線程中處理長時間運行的請求。本文將跟你一起探討如何以線程安全的方式來編寫類。
  • 吃透這篇ConcurrentHashMap源碼,就夠了
    解決使用AtomicStampedReference和AtomicMarkableReference實現標記的功能。四、Java中的原子操作( atomic operations)原子操作指的是在一步之內就完成而且不能被中斷,原子操作在多線程環境中是線程安全的,無需考慮同步的問題。