深刻淺出ConcurrentHashMap1.8+CAS+volatile

1.深刻淺出CASjava

前言

CAS(Compare and Swap),即比較並替換,實現併發算法時經常使用到的一種技術,Doug lea大神在java同步器中大量使用了CAS技術,鬼斧神工的實現了多線程執行的安全性。CAS原理(也能夠理解爲樂觀鎖)保證了原子面試

CAS的思想很簡單:三個參數,一個當前內存值V、舊的預期值A、即將更新的值B,當且僅當預期值A和內存值V相同時,將內存值修改成B並返回true,不然什麼都不作,並返回false。算法

CAS缺點

CAS存在一個很明顯的問題,即ABA問題。數組

問題:若是變量V初次讀取的時候是A,而且在準備賦值的時候檢查到它仍然是A,那能說明它的值沒有被其餘線程修改過了嗎?緩存

若是在這段期間曾經被改爲B,而後又改回A,那CAS操做就會誤認爲它歷來沒有被修改過。針對這種狀況,java併發包中提供了一個帶有標記的原子引用類AtomicStampedReference,它能夠經過控制變量值的版原本保證CAS的正確性。安全

2.volatile關鍵字數據結構

前言多線程

volatile做爲java中的關鍵詞之一,用以聲明變量的值可能隨時會別的線程修改,使用volatile修飾的變量會強制將修改的值當即寫入主存,主存中值的更新會使緩存中的值失效(非volatile變量不具有這樣的特性,非volatile變量的值會被緩存,線程A更新了這個值,線程B讀取這個變量的值時可能讀到的並非是線程A更新後的值)。volatile會禁止指令重排。併發

 

  2.1 volatile特性jvm

 

volatile具備可見性、有序性,不具有原子性。

 

注意,volatile不具有原子性,這是volatile與java中的synchronized、java.util.concurrent.locks.Lock最大的功能差別,這一點在面試中也是很是容易問到的點。

 

下面來分別看下可見性、有序性、原子性:

 

原子性:若是你瞭解事務,那這個概念應該好理解。原子性一般指多個操做不存在只執行一部分的狀況,若是所有執行完成那沒毛病,若是隻執行了一部分,那對不起,你得撤銷(即事務中的回滾)已經執行的部分。可見性:當多個線程訪問同一個變量x時,線程1修改了變量x的值,線程一、線程2...線程n可以當即讀取到線程1修改後的值。有序性:即程序執行時按照代碼書寫的前後順序執行。在Java內存模型中,容許編譯器和處理器對指令進行重排序,可是重排序過程不會影響到單線程程序的執行,卻會影響到多線程併發執行的正確性。(本文不對指令重排做介紹,但不表明它不重要,它是理解JAVA併發原理時很是重要的一個概念)。3.volatile適用場景

 

適用於對變量的寫操做不依賴於當前值,對變量的讀取操做不依賴於非volatile變量。適用於讀多寫少的場景(由於讀操做不須要原子性)可用做狀態標誌。JDK中volatie應用:JDK中ConcurrentHashMap的Entry的value和next被聲明爲volatile,AtomicLong中的value被聲明爲volatile。AtomicLong經過CAS原理(也能夠理解爲樂觀鎖)保證了原子性。    

  2.2 volatile VS synchronized

  • volatile本質是在告訴jvm當前變量在寄存器(工做內存)中的值是不肯定的,須要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住。
  • volatile僅能使用在變量級別;synchronized則可使用在變量、方法、和類級別的
  • volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則能夠保證變量的修改可見性和原子性
  • volatile不會形成線程的阻塞;synchronized可能會形成線程的阻塞。
  • volatile標記的變量不會被編譯器優化;synchronized標記的變量能夠被編譯器優化

深刻淺出ConcurrentHashMap1.8  (轉載 https://www.jianshu.com/p/c0642afe03e0)

對於上面的文章的總結

  1. jdk1.7 ConcurrentHashMap採用 分段鎖的機制,實現併發的更新操做,底層採用數組+鏈表的存儲結構,jdk1.8的實現已經拋棄了Segment分段鎖機制,利用CAS+Synchronized來保證併發更新的安全,底層採用數組+鏈表+紅黑樹的存儲結構。

  2. 鍵值對節點使用的Node

  • Node:保存key,value及key的hash值的數據結構。

 

其中value和next都用volatile修飾,保證併發的可見性。

3. put操做採用CAS+synchronized實現併發插入或更新操做

4.其餘的和hashMap 差很少。

5.線程安全,不容許有null值null 鍵

相關文章
相關標籤/搜索