業(yè)精于勤而荒于嬉,行成于思而毀于隨。
java內(nèi)存模型
java內(nèi)存模型(java memory model)是一種規(guī)范,是解決多線程在用共享內(nèi)存時,因為3級緩存,編譯器重排,cpu亂序執(zhí)行,導(dǎo)致的線程安全問題。
3種問題:原子性,可見性,有序性
關(guān)鍵字volatile
保證可見性,有序性
在實現(xiàn)雙重檢測單例時,就是因為利用了有序性,保證創(chuàng)建對象時按照分配內(nèi)存->內(nèi)存中創(chuàng)建對象-> 變量指向內(nèi)存的執(zhí)行順序。
不能保證原子性,導(dǎo)致一些依賴原值的修改操作,在多線程中會出現(xiàn)問題。
可以用AtomicInteger->longAdder(分段cas并發(fā)時性能好)來實現(xiàn)線程安全。(基于CAS)
寫操作前插入寫寫、寫操作后添加寫讀、讀操作前添加讀讀、讀操作后添加讀寫內(nèi)存屏障,保證可見性和有序性。
實現(xiàn)線程安全思路
- 鎖(
s鎖,AQS鎖) - cas(
AtomicInteger) - 一個線程一套(
ThreadLocal)
S鎖
jdk1.5實現(xiàn),是個笨鎖,操作有用戶態(tài)內(nèi)核的上下文切換。
jdk1.6升級了,根據(jù)競爭程度一級一級升級。這里也涉及到了自旋鎖,因為自旋鎖在競爭比較激烈比較費(fèi)cpu,所以最后轉(zhuǎn)為笨鎖,一了百了。

CAS算法
內(nèi)存值,舊值,新值。
線程舊值到新值運(yùn)算完之后,回寫內(nèi)存值時,對比內(nèi)存值和舊值是否相等。
ABA問題可以加版本號處理。
爭搶比較多比較費(fèi)cpu,但是比起s鎖沒有上下文切換開銷。
AQS抽象同步隊列
state為0說明沒有正在運(yùn)行的線程,可以直接運(yùn)行,運(yùn)行會把state改為1,這時候如果還是這個線程重入加鎖,會再進(jìn)行累加。
雙向鏈表(CHL),有正在運(yùn)行的線程,又不是自己,r鎖默認(rèn)是非公平鎖,會先加到尾插到鏈表里。
r鎖默認(rèn)是非公平鎖,可以創(chuàng)建的時候指定,非公平鎖時新加鎖的線程會先cas2次去爭搶鎖,搶到就繼續(xù)執(zhí)行,否則park放到鏈表尾部。公平鎖模式,會直接放到park鏈表尾部。非公平鎖具有更高的吞度量,因為新加入線程可能直接執(zhí)行,沒有暫停,放入隊列,再喚醒的開銷。
Locksupport.park
- 響應(yīng)中斷,但不拋出異常。
- 底層permit布爾值,控制掛起執(zhí)行。
封裝的一些類:
-
ReentrantLock
比起s鎖,公平鎖,可中斷,有狀態(tài)。
代碼塊,需要手動釋放。
lock.Condition實現(xiàn)了s鎖的wait nofity機(jī)制。
對應(yīng)await,signal方法。 -
ReentrantReadWriteLock讀寫鎖。 -
Semaphore信號量,控制線程的數(shù)量。
acquire()數(shù)量加一,滿了阻塞。
release()數(shù)量減一。 -
CountDownLatch倒計時 實現(xiàn)線程同時運(yùn)行。
await()阻塞,等待數(shù)減到0。
countdown()數(shù)量減一。 -
CyclicBarrier循環(huán)屏障(比起countdownLatch可以復(fù)用reset)
await()阻塞,當(dāng)所有數(shù)量線程都走到此步,繼續(xù)執(zhí)行。
ThreadLocal
http://www.itdecent.cn/p/a20af7b7d113
