做爲一款公用平臺,JDK 自己也爲併發程序的性能絞盡腦汁,在 JDK 內部也想盡一切辦法提供併發時的系統吞吐量。這裏,我將向你們簡單介紹幾種 JDK 內部的 "鎖" 優化策略。數組
一、 鎖偏向併發
鎖偏向是一種針對加鎖操做的優化手段。函數
若是一個線程得到了鎖,那麼鎖就進入偏向模式。當這個線程再次請求鎖時,無須再作任何同步操做。這樣就節省了大量有關鎖申請的操做,從而提升了程序性能。性能
所以,對於幾乎沒有鎖競爭的場合,偏向鎖有比較紅啊的優化效果,由於連續屢次極有多是同一個線程請求相同的鎖。而對於鎖競爭比較激烈的場合,其效果不佳。由於在競爭激烈的場合,最有可能的狀況是每次都是不一樣的線程來請求相同的鎖。點擊這裏瞭解幾種常見的鎖。優化
二、 輕量級鎖ui
若是偏向鎖失敗,即上一個請求的鎖的線程和這個線程不是同一個。偏向鎖失敗意味者不能避免作同步操做。此時,虛擬機並不會當即掛起線程。他會使用一種成爲輕量級鎖的優化手段。操作系統
輕量級鎖的操做也很方便,它只是簡單地將對象頭部做爲指針,指向蚩尤鎖的線程堆棧的內部,來判斷一個線程是否持有對象鎖。 若是線程得到輕量級鎖成功,則能夠順利進入臨界區。若是輕量級鎖失敗,則表示其餘線程搶先爭奪了鎖,那麼當前線程的鎖請求就會膨脹爲重量級鎖。點擊這裏瞭解幾種常見的鎖。線程
三、 自選鎖指針
鎖膨脹後,虛擬機爲了不線程真實地在操做系統層面掛起,虛擬機還會在作最後的努力–自選鎖。因爲當前線程暫時沒法得到鎖,可是何時能夠得到鎖是一個未知數。也許在CPU幾個時鐘週期後,就能夠獲得鎖。若是這樣,簡單粗暴的掛起線程多是一種得不償失的操做,所以系統會進行一次賭注:它會假設在不久的未來,線程能夠獲得這把鎖。server
所以虛擬機讓當前線程作個空循環,在通過若干次循環後,若是能夠獲得鎖,那麼就順利進入臨界區。若是還不能獲得鎖,纔會真實地將線程在操做系統層面掛起。
四、 鎖消除
鎖消除是一種更完全的鎖優化。Java虛擬機在JIT編譯時,經過對運行上下文的掃描,去除不可能存在共享資源競爭的鎖。經過鎖消除,能夠節省毫無心義的請求鎖時間。
下面這種這種狀況,咱們使用vector, 而vector內部使用了synchronize請求鎖。
publicString[] createStrings(){
Vector v=newVector();
for(inti=0;i<100;i++){
v.add(Integer.toString(i));
}
return v.toArray(newString[]{}); }
因爲V只在函數 createStrnigs 中使用,所以它只是一個單純的局部變量。局部變量是在線程棧上分配的,屬於線程私有額數據,所以不可能被其餘線程訪問。因此,在這種狀況下,Vector內部全部加鎖同步都是沒有必要的。若是虛擬機檢測到這種狀況,就會將這些無用的鎖操做去除。點擊這裏瞭解幾種常見的鎖。
鎖消除涉及的一項關鍵技術爲逃逸分析。所謂逃逸分析就是觀察某一個變量是否會逃出某一個做用域。在本例中,變量v顯然沒有逃出createString 函數以外。以此爲基礎,虛擬機才能夠大膽的將v內部的加鎖操做去除。若是createStrings 返回的不是String數組,而是v自己,那麼就認爲變量v逃逸出了當前函數,也就是說v有可能被其餘線程訪問。如是這樣,虛擬機就不能消除v中的鎖操做。
逃逸分析必須在 -server 模式下進行,可使用 -XX:DoEscapeAnalysis 參數打開逃逸分析,使用 -XX:+EliminateLocks 參數能夠打開鎖消除。