讀寫鎖,也就是讀寫分離鎖。
讀寫分離鎖可以有效地減少鎖競争,提升系統性能。用鎖分離的機制來提升性能非常容易了解,比如,A1、A2、A3線程進行寫操作,B1、B2、B3線程進行讀操作,如果使用重入鎖或者内部鎖,從理論上說所有讀與讀之間、讀與寫之間、寫與寫之間都是串行操作的。當B1線程進行讀取時,B2、B3線程則需要等待鎖。由于讀操作并不對資料的完整性造成破壞,這種等待顯然是不合理的。是以,讀寫鎖就有了發揮作用的地方。
在這種情況下,讀寫鎖允許多個線程同時讀,使得B1、B2、B3線程之間實作真正的并行。但是,考慮到資料完整性,寫與寫之間和讀與寫之間的操作依然是需要互相等待和持有鎖的。總的來說,讀寫鎖的通路限制情況如下(見表3.1)。
l 讀與讀不互斥:讀與讀之間非阻塞。
l 讀與寫互斥:讀阻塞寫,寫也會阻塞讀。
l 寫與寫互斥:寫與寫之間阻塞。
作為一款共用平台,JDK本身也為并發程式的性能絞盡腦汁。在JDK内部也想盡一切辦法提高并發時的系統吞吐量。這裡将向大家簡單介紹幾種JDK内部的“鎖”優化政策。
鎖偏向
鎖偏向是一種針對加鎖操作的優化手段。它的核心思想是:如果一個線程獲得了鎖,那麼鎖就進入偏向模式。當這個線程再次請求鎖時,無須再做任何同步操作。這樣就節省了大量有關鎖請求的操作,進而提高了程式性能。是以,對于幾乎沒有鎖競争的場合,鎖偏向有比較好的優化效果,因為極有可能是同一個線程連續多次請求相同的鎖。而對于鎖競争比較激烈的場合,其效果不佳。因為在競争激烈的場合,最有可能的情況是,每次都是不同的線程來請求相同的鎖。這樣偏向模式會失效,是以還不如不啟用鎖偏向。使用Java虛拟機參數-XX:+UseBiasedLocking可以開啟鎖偏向。
輕量級鎖
如果鎖偏向失敗,那麼虛拟機并不會立即挂起線程,它還會使用一種被稱為輕量級鎖的優化手段。輕量級鎖的操作也很友善,它隻是簡單地将對象頭部作為指針指向持有鎖的線程堆棧的内部,來判斷一個線程是否持有對象鎖。如果線程獲得輕量級鎖成功,則可以順利進入臨界區。如果輕量級鎖加鎖失敗,則表示其他線程搶先争奪到了鎖,那麼目前線程的鎖就會膨脹為重量級鎖。
自旋鎖
鎖膨脹後,為了避免線程真實地在作業系統層面挂起,虛拟機還會做最後的努力—自旋鎖。目前線程暫時無法獲得鎖,而且什麼時候可以獲得鎖是一個未知數,也許在幾個CPU時鐘周期後就可以獲得鎖。如果這樣,簡單粗暴地挂起線程可能是一種得不償失的操作。系統會假設在不久的将來,線程可以得到這把鎖。是以,虛拟機會讓目前線程做幾個空循環(這也是自旋的含義),在經過若幹次循環後,如果可以得到鎖,那麼就順利進入臨界區;如果還不能獲得鎖,才會真的将線程在作業系統層面挂起。
鎖消除
鎖消除是一種更徹底的鎖優化方式。Java虛拟機在JIT編譯時,通過對運作上下文的掃描,去除不可能存在共享資源競争的鎖。通過鎖消除,可以節省毫無意義的請求鎖時間。
說到這裡,細心的讀者可能會産生疑問,如果不存在競争,為什麼程式員還要加上鎖呢?這是因為在Java軟體開發過程中,我們必然會使用一些JDK的内置API,比如StringBuffer、Vector等。你在使用這些API的時候,也許根本不會考慮它們到底是如何實作的。比如,你很有可能在一個不可能存在并發競争的場合使用Vector。而衆所周知,Vector内部使用了synchronized請求鎖,例如下面的代碼:
- public String[] createStrings(){
- Vector<String> v=new Vector<String>();
- for(int i=0;i<100;i++){
- v.add(Integer.toString(i));
- }
- return v.toArray(new String[]{});
- }
注意上述代碼中的Vector,由于變量v隻在createStrings()方法中使用,是以它隻是一個單純的局部變量。局部變量是線上程棧中配置設定的,屬于線程私有的資料,是以不可能被其他線程通路。在這種情況下,Vector内部所有的加鎖同步都是沒有必要的。如果虛拟機檢測到這種情況,就會将這些無用的鎖操作去除。
鎖消除涉及的一項關鍵技術為逃逸分析。所謂逃逸分析就是觀察某一個變量是否會逃出某一個作用域。在本例中,變量v顯然沒有逃出createStrings()方法。以此為基礎,虛拟機才可以大膽地将變量v内部的加鎖操作去除。如果createStrings()方法傳回的不是String數組,而是變量v本身,那麼就認為變量v逃逸出了目前方法,也就是說變量v有可能被其他線程通路。如果是這樣,虛拟機就不能消除變量v中的鎖操作。
逃逸分析必須在-server模式下進行,可以使用-XX:+DoEscapeAnalysis參數打開逃逸分析功能。使用-XX:+EliminateLocks參數可以打開鎖消除功能。
内容摘自《實戰Java高并發程式設計(第3版)》,本書适合:所有java從業人員,所有資料庫工程師閱讀。 邏輯順暢。全書脈絡清晰,從Java高并發程式的設計基礎開始由底層原理落實到具體案例,環環相扣,完整流暢。結構嚴謹。總體上循序漸進,逐漸提升。每一章都各自有鮮明的側重點,有利于讀者快速抓住重點。 實用性強。本書注重實戰,采用了理論結合實踐的編寫方法,給重要的知識點都安排了代碼執行個體,幫助讀者在工作中實戰應用。