首先來看公平鎖和非公平鎖,我們默認使用的鎖是非公平鎖,只有當我們顯示設置為公平鎖的情況下,才會使用公平鎖,下面我們簡單看一下公平鎖的源碼,如果等待隊列中沒有節點在等待,則占有鎖,如果已經存在等待節點,則返回失敗,由后面的程序去將此線程加入等待隊列
通過上面的代碼,我們可以推斷,當使用公平鎖的情況下,并且同一個線程的執行時間較長時,線程內部進行了多次的鎖的獲取和釋放,效率非常低下,可以參加Lesson8中的demo:
demo Lesson8LockIntPerform:在使用ReentrantLock加非公平鎖的情況下100個線程循環下單數為:857239882
demo Lesson8LockIntPerform:在使用ReentrantLock加非公平鎖的情況下100個線程循環下單數為:860364303
demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平鎖的情況下100個線程循環下單數為:19153640
demo Lesson8LockFairIntPerform:在使用ReentrantLock加公平鎖的情況下100個線程循環下單數為:19076567
上面的demo中,在使用公平鎖的情況下性能明顯降低,非公平鎖的性能是公平鎖性能的幾十倍以上,這和公平鎖每次試圖占有鎖時,都必須先要進等待隊列,按照FIFO的順序去獲取鎖,因此在我們的實驗情景下,使用公平鎖的線程進行了頻繁切換,而頻繁切換線程,性能必然會下降的厲害,這也告誡了我們在實際的開發過程中,在需要使用公平鎖的情景下,務必要考慮線程的切換頻率。
接下來我們來看一下讀寫鎖,通過看讀寫鎖的實現源碼,我們可以發現,讀鎖和寫鎖共用同一個等待隊列,那么在采用非公平鎖的情況下,如果讀鎖的線程執行時間比較長,并且讀鎖的并發比較高,那么寫鎖的線程便永遠都拿不到鎖,那么實際的情況會不會是這樣呢?
demo?Lesson3WriteReadLock:此demo的讀線程在不斷的占用讀鎖,按照推論,寫鎖的線程是沒有機會獲取到鎖的,但是實際情況是寫鎖的線程可以正常的獲取到鎖,那么是什么原因使得寫鎖的線程可以獲取到鎖的了?通過查看源代碼,會發現有這樣的一個方法:
上面的方法,實現了一個新的讀線程獲取鎖的中斷,它會讀取等待隊列中下一個等待鎖的線程,如果它是獲取寫鎖的線程,那么此方法返回為真,調用它的程序會把這個試圖獲取讀鎖的線程加入到等待隊列,從而終止了讀線程一直都在占有鎖的情況。