在Java併發編程中,公平鎖與非公平鎖是很常見的概念,ReentrantLock、ReadWriteLock默認都是非公平模式,非公平鎖的效率為何高於公平鎖呢?究竟公平與非公平有何區別呢?
公平鎖與非公平鎖的一個重要區別就在於上圖中的2、6、10那個步驟,對應源碼如下:
分析以上代碼,我們可以看到公平鎖就是在獲取鎖之前會先判斷等待隊列是否為空或者自己是否位於隊列頭部,該條件通過才能繼續獲取鎖。
在結合兔子喝水的圖分析,非公平鎖獲取所得順序基本決定在9、10、11這三個事件發生的先後順序,
1、若在釋放鎖的時候總是沒有新的兔子來打擾,則非公平鎖等於公平鎖;
2、若釋放鎖的時候,正好一個兔子來喝水,而此時位於隊列頭的兔子還沒有被喚醒(因為線程上下文切換是需要不少開銷的),此時後來的兔子則優先獲得鎖,成功打破公平,成為非公平鎖;
其實對於非公平鎖,只要線程進入了等待隊列,隊列裡面依然是FIFO的原則,跟公平鎖的順序是一樣的。因為公平鎖與非公平鎖的release()部分代碼是共用AQS的代碼。
上文說到的線程切換的開銷,其實就是非公平鎖效率高於公平鎖的原因,因為非公平鎖減少了線程掛起的幾率,後來的線程有一定幾率逃離被掛起的開銷。
閱讀更多 果大爺的幸福生活 的文章