本文爲原創,如需轉載請註明來處便可。java
現代jdk juc包源碼解讀算法
使用場景分析編程
使用場景解讀api
互斥同步(mutual exclusion & synchronization)是常見的一種併發正確性保障手段。同步是指多個線程併發訪問共享數據時,保證共享數據在同一時刻只能被一個線程(或者是一些,使用信號量的時候)使用。
互斥是實現同步的一種手段,如臨界區,互斥量,信號量都是主要的互斥實現方式。
互斥是因,同步是果。互斥是方法,同步時目的。安全
最基本的互斥實現手段就是synchronized關鍵字。synchronized關鍵字通過編譯以後,會在同步塊的先後分別造成monitorenter和monitorexit字節碼指令,這兩個字節碼都須要一個reference類型的參數來指明鎖定和解鎖的對象。若是Java程序中的synchronized明確指定了對象參數,那就是這個對象的reference,若是沒有明確指定,那就根據synchronized修飾的是實例方法仍是類方法,去取對應的對象實例或class對象來做爲鎖對象。架構
在執行monitorenter指令時,首先要嘗試獲取對象的鎖。若是這個對象沒有被鎖定,或者當前線程已經擁有了那個對象的鎖,把鎖的計數器加1,相應的,在執行monitorexit時,將計數器減1,當爲0時,鎖就被釋放。若是獲取鎖失敗,那麼當前線程就要阻塞等待,直到對象鎖被另外一個線程釋放。併發
TODO:【探究】探究reentrantlock鎖(能夠和其餘類型的鎖一塊兒總結研究)【源碼級別】 TODO:【探索】深刻探索juc包【源碼級別】
樂觀併發策略得益於硬件指令集的發展,硬件保證一個從語義上看起來須要屢次操做的行爲只須要一條處理器指令集就能夠完成,以下:函數
加載連接/條件存儲(LL/SC)源碼分析
cas指令須要3個操做數,分別是內存位置(再Java中能夠簡單的理解爲變量的內存地址,用V表示),舊的預期值(A),和新值(B)。CAS指令執行時,當且僅當V的值符合舊的預期值A時,處理器用B更新A的值,不然不執行更新,但不管是否更新,返回的都是V的舊值。上述操做是一個原子操做。
TODO:【探索】從硬件指令集的角度探索cas的原子性。cas操做不是完美的,存在這樣一個邏輯漏洞,簡稱 「ABA」 問題:
一個線程one從內存位置V中取出A,這時候另外一個線程two也從內存中取出A,而且two進行了一些操做變成了B,而後two又將V位置的數據變成A,這時候線程one進行CAS操做發現內存中仍然是A,而後one操做成功
TODO:【探索】cas操做使用場景分析。
若是一個方法自己就不涉及共享數據,那就天然無需同步措施來保證正確性。
可重入代碼:
##
這種代碼也叫作純代碼,能夠在代碼執行的任什麼時候刻中斷它,轉而去執行另一段代碼(包括遞歸調用它自己),而在控制權返回後,原來的程序不會發生任何錯誤。
##
全部的可重入代碼都是線程安全的,可是並不是全部線程安全的代碼都是可重入的。可重入代碼都有一些共同的特徵,如不依賴堆上共享數據和公共的系統資源,用到的狀態量是從參數傳入,不調用非可重入的方法等。
##
能夠經過簡單的原則來判斷是否可重入性:若是一個方法,他的返回結果是能夠預測的,只要輸入了相同的數據,就能夠返回相同的結果,那麼他就能夠知足可重入的要求,固然也就是線程安全的。
線程本地存儲:
##
java.lang.ThreadLocal類能夠實現線程本地存儲的功能。每個線程的Thread對象都有一個ThreadLocalMap對象,這個對象存儲了以 ThreadLocal.threadLocalHashCode爲鍵,以本地線程變量爲值得K-V值對,ThreadLocal對象就是當前線程的ThreadLocalMap訪問入口,每個ThreadLocal對象都包含了獨一無二的threadLocalHashCode值,就能夠找到對應的本地線程變量。
##
大部分使用消費序列的架構模式都會使用線程本地存儲。
TODO:【探究】詳細探究ThreadLocal原理及其源碼實現,必要的話單開一個po。
TODO:【延申】嘗試探究消息服務隊列的線程模型以及消息架構。【參考rocketMQ,KAFKA】
TODO:【延申】探索本地線程存儲的使用場景,並解讀。
參考: 《深刻理解Java虛擬機》第二版 《Java併發編程之美》 《rocket mq實戰》