1.概述數組
在要點提煉| 理解JVM以內存模型&線程中主要介紹了虛擬機如何實現『併發』,如今的關注點是虛擬機如何實現『高效』。安全
2.線程安全多線程
在實現高效以前,首先須要保證併發的正確性,所以本節先介紹線程安全。併發
a.定義:當多個線程訪問一個對象時,若是不用考慮這些線程在運行時環境下的調度和交替執行,也不須要進行額外的同步,或者在調用方進行任何其餘的協調操做,調用這個對象的行爲均可以得到正確的結果,那這個對象是線程安全的。函數
要求線程安全的代碼都必須具有一個特徵: 代碼自己封裝了全部必要的正確性保障手段(如互斥同步等),令調用者無須關心多線程的問題,更無須本身採起任何措施來保證多線程的正確調用。佈局
b.分類:按照線程安全的程度由強至弱分紅五類post
final
關鍵字修飾;final
。Vector
、HashTable
、Collections#synchronizedCollection()
包裝的集合...ArrayList
和HashMap
...c.線程安全的實現性能
可分紅兩大手段,本篇重點在虛擬機自己測試
- 經過代碼編寫實現線程安全
- 經過虛擬機自己實現同步與鎖
①互斥同步(Mutual Exclusion&Synchronization)優化
互斥是因,同步是果;互斥是方法,同步是目的。
synchronized
關鍵字:
monitorenter
和monitorexit
這兩個字節碼指令,並經過一個reference
類型的參數來指明要鎖定和解鎖的對象。若明確指定了對象參數,則取該對象的reference
;不然,會根據synchronized
修飾的是實例方法仍是類方法去取對應的對象實例或Class對象來做爲鎖對象。monitorenter
指令時先要嘗試獲取對象的鎖。若該對象沒被鎖定或者已被當前線程獲取,那麼鎖計數器+1;而在執行monitorexit
指令時,鎖計數器-1;當鎖計數器=0時,鎖就被釋放;若獲取對象鎖失敗,那當前線程會一直被阻塞等待,直到對象鎖被另一個線程釋放爲止。synchronized
同步塊對同一條線程來講是可重入的,不會出現自我鎖死的問題;還有,同步塊在已進入的線程執行完以前,會阻塞後面其餘線程的進入。ReentrantLock
:
synchronized
很類似,且均可重入。synchronized
的不一樣:
synchronized
是非公平的,即在鎖被釋放時,任何一個等待鎖的線程都有機會得到鎖。ReentrantLock
默認狀況下也是非公平的,但能夠經過帶布爾值的構造函數改用公平鎖。ReentrantLock
對象能夠經過屢次調用newCondition()
同時綁定多個Condition
對象。而在synchronized
中,鎖對象的wait()
和notify()
或notifyAl()
只能實現一個隱含的條件,若要和多於一個的條件關聯不得不額外地添加一個鎖。synchronized
能實現需求的狀況下,優先考慮使用它來進行同步。下兩張圖是二者在不一樣處理器上的吞吐量對比。②非阻塞同步(Non-Blocking Synchronization):
③無同步方案
知足可重入性的代碼必定是線程安全的,反之,知足線程安全的代碼不必定是可重入的。
ThreadLocal
類可實現線程本地存儲的功能:每一個線程的Thread
對象中都有一個ThreadLocalMap對象,它存儲了一組以ThreadLocal.threadLocalHashCode爲key、以本地線程變量爲value的鍵值對,而ThreadLocal對象就是當前線程的ThreadLocalMap的訪問入口,也就包含了一個獨一無二的threadLocalHashCode值,經過這個值就能夠在線程鍵值值對中找回對應的本地線程變量。3.鎖優化
解決併發的正確性以後,爲了能在線程之間更『高效』地共享數據、解決競爭問題、提升程序的執行效率,下面介紹五種鎖優化技術。
a.適應性自旋(Adaptive Spinning)
b.鎖消除(Lock Elimination)
c.鎖粗化(Lock Coarsening)
通常狀況下,會將同步塊的做用範圍限制到只在共享數據的實際做用域中才進行同步,使得須要同步的操做數量儘量變小,保證就算存在鎖競爭,等待鎖的線程也能儘快拿到鎖。
但若是反覆操做對同一個對象進行加鎖和解鎖,即便沒有線程競爭,頻繁地進行互斥同步操做也會致使沒必要要的性能損耗,此時,虛擬機將會把加鎖同步的範圍粗化到整個操做序列的外部,這樣只需加一次鎖。
d.輕量級鎖(Lightweight Locking)
首先先理解HotSpot虛擬機的對象頭的內存佈局:分爲兩部分
- 第一部分用於存儲對象自身的運行時數據,這部分被稱爲Mark Word,是實現輕量級鎖和偏向鎖的關鍵。如哈希碼、GC分代年齡等。
- 另一部分用於存儲指向方法區對象類型數據的指針,若是是數組對象還會有一個額外的部分用於存儲數組長度。
01
),虛擬機會在當前線程的棧幀中創建一個名爲Lock Record的空間,用於存儲鎖對象Mark Word的拷貝。以下圖。以後虛擬機會嘗試用CAS操做將對象的Mark Word更新爲指向Lock Record的指針。若更新動做成功,那麼當前線程就擁有了該對象的鎖,且對象Mark Word的鎖標誌位變爲00
,即處於輕量級鎖定狀態;反之,虛擬機會先檢查對象的Mark Word是否指向當前線程的棧幀,若當前線程已有該對象的鎖,可直接進入同步塊繼續執行,不然說明改對象已被其餘線程搶佔。以下圖。
另外,若是有兩條以上的線程爭用同一個鎖,那輕量級鎖就再也不有效,要膨脹爲重量級鎖,鎖標誌位變爲
10
,Mark Word中存儲的就是指向重量級鎖的指針,後面等待鎖的線程也要進入阻塞狀態。
e.偏向鎖(Biased Locking)
01
,即偏向模式,同時使用CAS操做把獲取到這個鎖的線程ID記錄在對象的Mark Word中。若操做成功,持有偏向鎖的線程之後每次進入這個鎖相關的同步塊時均可再也不進行任何同步操做。01
或輕量級鎖定00
的狀態,後續的同步操做就如輕量級鎖執行過程。以下圖。