final域、Atomic和ThreadLocal
解決併發2種方式
對於併發工作,需要某種方式來防止兩個任務同時訪問相同的資源,至少在關鍵階段不能出現這種衝突情況。
- 資源被一個任務使用時,在其上加鎖
- 根除對變數的共享。執行緒本地儲存是一種自動化機制,可以為使用相同變數的每個不同的執行緒都建立不同的儲存。因此,如果你有5個執行緒都要使用變數x所表示的物件,那執行緒本地儲存就會生成5個用於x的不同的儲存塊。它使得你可以將狀態與執行緒關聯起來。建立和管理執行緒本地儲存可以由java.lang.ThreadLocal類來實現。
final
對於final域,編譯器和處理器要遵守兩個重排序規則
- 在建構函式內對一個final域的寫入,與隨後把這個被構造物件的引用賦值給一 個引用變數,這兩個操作之間不能重排序。
- 初次讀一個包含final域的物件的引用,與隨後初次讀這個final域,這兩個操 作之間不能重排序。
寫final域重排序規則
- JMM禁止編譯器把final域的寫重排序到建構函式之外。
- 編譯器會在final域的寫之後,建構函式return之前,插入一個 StoreStore屏障。這個屏障禁止處理器把final域的寫重排序到構造 函式之外
讀域的重排序規則
- 在一個執行緒中,初次讀物件引用與初次讀該物件包含的final 域,JMM禁止處理器重排序這兩個操作,編譯器會在讀final 域操作的前面插入一個LoadLoad屏障。
Happens-Before
定義
- 是一種可見性規則,它表達的含義是前面一個操作的結 果對後續操作是可見的,是對編譯器和處理器重排序的規則
規則
程式順序規則 執行緒中的每個操作,happens- before 於該執行緒中的任意後續操作
監視器鎖規則 對一個鎖的解鎖 Happens-Before 於後續對這個鎖的加鎖
Volatile變數規則 對一個volatile域的寫,happens-before於任意後續對這個volatile 域的讀
傳遞性 如果A happens-before B,且B happens-before C,那麼A happensbefore C
start()規則 如果執行緒A執行操作ThreadB.start()(啟動執行緒B),那麼A執行緒的 ThreadB.start()操作happens-before於執行緒B中的任意操作
Join()規則 如果執行緒A執行操作ThreadB.join()併成功返回,那麼執行緒B中的任意 操作happens-before於執行緒A從ThreadB.join()操作成功返回
Atomic(無鎖工具的典範)
原子性問題解決
- synchronized、Lock
- J.U.C包下的Atomic類
Atomic實現原理 參考這篇
瞭解unsafe類 是java提供的獲得對物件記憶體地址訪問的類, getIntVolatile(var1, var2) 獲取執行緒間共享的變數
如AtomicInteger
- 建構函式,把數值放進成員變數中,value宣告為volatile型別
public AtomicInteger(int initialValue) { value = initialValue; }
- value的值通過內部this和valueOffset找到地址進行CAS操作
ABA問題
解決辦法:加入版本號或時間戳等標誌,如使用AtomicMarkableReference,AtomicStampedReference
由於compareAndSet只能一次改變一個值,無法同時改變newReference和newStamp,所以在實現的時候,在內部定義了一個類Pair類將newReference和newStamp變成一個物件,進行CAS操作的時候,實際上是對Pair物件的操作,Pair有2個成員變數: T reference; int stamp;
public boolean compareAndSet(V expectedReference, V newReference,
int expectedStamp,int newStamp) {
Pair<V> current = pair;
return expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference && newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
Atomic包中的類按照操作的資料型別可以分成4組, 我們一般常用的AtomicInteger、AtomicReference和AtomicStampedReference
- AtomicBoolean,AtomicInteger,AtomicLong
執行緒安全的基本型別的原子性操作
- AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
執行緒安全的陣列型別的原子性操作,它操作的不是整個陣列,而是陣列中的單個元素
- AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
基於反射原理物件中的基本型別(長整型、整型和引用型別)進行執行緒安全的操作
- AtomicReference ,AtomicMarkableReference,AtomicStampedReference
執行緒安全的引用型別及防止ABA問題的引用型別的原子操作
在LongAdder 與AtomicLong有區別
Atomic*(CAS+自旋)遇到的問題是,用於低併發場景。
LongAddr(CAS樂觀鎖保證原子性,通過自旋保證當次修改的最終修改成功,通過降低鎖粒度(多段鎖))加了分段鎖,當競爭不激烈的時候,所有執行緒都是通過CAS對同一個變數(Base)進行修改,當競爭激烈的時候,會將根據當前執行緒雜湊到對於Cell上進行修改(多段鎖)
ThreadLocal的使用和原理
作用
- ThreadLocal用於儲存某個執行緒共享變數,是執行緒區域性變數,同一個 ThreadLocal 所包含的物件,在不同的 Thread 中有不同的副本。
內部組成
- Thread類中有個變數threadLocals,這個型別為ThreadLocal中的一個內部類ThreadLocalMap,這個類沒有實現map介面,就是一個普通的Java類,但是實現的類似map的功能。ThreadLocalMap是ThreadLocal的內部類,每個資料用Entry儲存,其中的Entry繼承與WeakReference
雜湊衝突:
ThreadLocal中的hash code非常簡單,就是呼叫AtomicInteger的getAndAdd方法,引數是個固定值0x61c88647。ThreadLocalMap的結構非常簡單隻用一個陣列儲存,並沒有連結串列結構,當出現Hash衝突時採用線性查詢的方式,所謂線性查詢,就是根據初始key的hashcode值確定元素在table陣列中的位置,如果發現這個位置上已經有其他key值的元素被佔用,則利用固定的演算法尋找一定步長的下個位置,依次判斷,直至找到能夠存放的位置。如果產生多次hash衝突,處理起來就沒有HashMap的效率高,為了避免雜湊衝突,使用盡量少的threadlocal變數
注:一個ThreadLocal只能儲存一個變數的副本,如果需要多個,就得建立多個變數;我們確定使用完需要執行remove避免記憶體洩漏,使用 ThreadLocal 的時候,最好要宣告為靜態的
簡單說說get方法
主要邏輯如下:
- 先獲取當前執行緒t;
- 然後獲取ThreadLocalMap;
- 如果map不為空,則以當前物件(ThreadLocal物件)為key獲取value;
- 如果map為空,則執行初始化操作;
如果是第一次呼叫get時ThreadLocalMap如果還沒有的話是如何初始化,如下
setInitialValue的主要邏輯如下:
- 首先通過initialValue方法生成初始值;
- 然後獲取ThreadLocalMap;
- 如果map不為空,則將第1步生成的值set進去,以當前物件(ThreadLocal物件)為key;
- 如果map為空,則new一個ThreadLocalMap出來;
- 返回生成的初始值;
ThreadLocal結構圖
相關文章
- Java中syncrhoized ,reentrantLock ,Atomic ,Lock ,ThreadLocal ,transient ,volatile,物件鎖和類鎖JavaZedReentrantLockthread物件
- 併發程式設計之ThreadLocal、Volatile、synchronized、Atomic關鍵字程式設計threadsynchronized
- C++ 中的 volatile 和 atomicC++
- C++ atomic 和 memory ordering 筆記C++筆記
- CAS演算法和ThreadLocal演算法thread
- final修飾和static final修飾的區別
- ThreadLocal和ThreadLocalMap原始碼分析thread原始碼
- 淺談synchronized、Lock、ThreadLocal和semaphoresynchronizedthread
- Java中ThreadLocal的用法和原理Javathread
- ThreadLocal原始碼和圖文分析thread原始碼
- ThreadLocal 原理和使用場景分析thread
- Atomic原子操作原理剖析
- Atomic 原子類詳解
- 原子操作atomic_t
- 匿名內部類訪問final區域性變數變數
- iOS中atomic和nonatomic區別及內部實現iOS
- 和朱曄一起復習Java併發(四):AtomicJava
- (基礎系列)atomic原子變數類的用法、原理和用途變數
- 談談引用和Threadlocal的那些事thread
- ThreadLocalthread
- 面試中的 ThreadLocal 原理和使用場景面試thread
- 基礎篇:JAVA引用型別和ThreadLocalJava型別thread
- 使用ThreadLocal變數的時機和方法thread變數
- 併發程式設計之:Atomic程式設計
- (201)Atomic*實現原理
- java Atomic 基本資料型別Java資料型別
- C++多執行緒:atomicC++執行緒
- Threadlocal詳解(ThreadLocal,InheritTableThreadLocal,TransmittableThreadLocal)threadMIT
- ThreadLocal分析thread
- ThreadLocal解析thread
- ThreadLocal理解thread
- 解析ThreadLocalthread
- ThreadLocal 剖析thread
- ThreadLocal 解析thread
- 理解ThreadLocalthread
- final
- java中的static和final關鍵字Java
- Java基礎——final和static關鍵字Java