1.深刻淺出CASjava
CAS(Compare and Swap),即比較並替換,實現併發算法時經常使用到的一種技術,Doug lea大神在java同步器中大量使用了CAS技術,鬼斧神工的實現了多線程執行的安全性。CAS原理(也能夠理解爲樂觀鎖)保證了原子面試
CAS的思想很簡單:三個參數,一個當前內存值V、舊的預期值A、即將更新的值B,當且僅當預期值A和內存值V相同時,將內存值修改成B並返回true,不然什麼都不作,並返回false。算法
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
對於上面的文章的總結
1. jdk1.7 ConcurrentHashMap採用 分段鎖的機制,實現併發的更新操做,底層採用數組+鏈表的存儲結構,jdk1.8的實現已經拋棄了Segment分段鎖機制,利用CAS+Synchronized來保證併發更新的安全,底層採用數組+鏈表+紅黑樹的存儲結構。
2. 鍵值對節點使用的Node
![](http://static.javashuo.com/static/loading.gif)
其中value和next都用volatile修飾,保證併發的可見性。
3. put操做採用CAS+synchronized實現併發插入或更新操做
4.其餘的和hashMap 差很少。
5.線程安全,不容許有null值null 鍵