您好,登錄后才能下訂單哦!
本篇文章為大家展示了Java 中怎么實現公平鎖與非公平鎖,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
公平鎖是指多個線程按照申請鎖的順序來獲取鎖,線程直接進入隊列中排隊,隊列中的第一個線程才能獲得鎖。公平鎖的優點是等待鎖的線程不會餓死。缺點是整體吞吐效率相對非公平鎖要低,等待隊列中除第一個線程以外的所有線程都會阻塞,CPU 喚醒阻塞線程的開銷比非公平鎖大。
非公平鎖是多個線程加鎖時直接嘗試獲取鎖,獲取不到才會到等待隊列的隊尾等待。但如果此時鎖剛好可用,那么這個線程可以無需阻塞直接獲取到鎖,所以非公平鎖有可能出現后申請鎖的線程先獲取鎖的場景。非公平鎖的優點是可以減少喚起線程的開銷,整體的吞吐效率高,因為線程有幾率不阻塞直接獲得鎖,CPU 不必喚醒所有線程。缺點是處于等待隊列中的線程可能會餓死,或者等很久才會獲得鎖。
上面的解釋可能優點抽象,下面我們通過一張圖來區別什么是公平鎖?什么是非公平鎖?
如上圖所示,假設有一口水井,有管理員看守,管理員有一把鎖,只有拿到鎖的人才能夠打水,打完水要把鎖還給管理員。每個過來打水的人都要管理員的允許并拿到鎖之后才能去打水,如果前面有人正在打水,那么這個想要打水的人就必須排隊。管理員會查看下一個要去打水的人是不是隊伍里排最前面的人,如果是的話,才會給你鎖讓你去打水;如果你不是排第一的人,就必須去隊尾排隊,這就是公平鎖。
但是對于非公平鎖,管理員對打水的人沒有要求。即使等待隊伍里有排隊等待的人,但如果在上一個人剛打完水把鎖還給管理員而且管理員還沒有允許等待隊伍里下一個人去打水時,剛好來了一個插隊的人,這個插隊的人是可以直接從管理員那里拿到鎖去打水,不需要排隊,原本排隊等待的人只能繼續等待。如下圖所示(還是打水的例子):
徹底的理解了 Java 中的公平鎖與非公平鎖后,我們來看看 Java 中的 ReentrantLock。
閱讀過 ReentrantLock 源碼的都知道,它里面有一個內部類 Sync,Sync 繼承 AQS(AbstractQueuedSynchronizer),添加鎖和釋放鎖的大部分操作實際上都是在 Sync 中實現的。它有公平鎖 FairSync 和非公平鎖 NonfairSync 兩個子類。ReentrantLock 默認使用非公平鎖,也可以通過構造器來顯示的指定使用公平鎖。
下面我們來看一下公平鎖與非公平鎖的加鎖方法的源碼:
通過上圖中的源代碼對比,我們可以明顯的看出公平鎖與非公平鎖的 lock() 方法唯一的區別就在于公平鎖在獲取同步狀態時多了一個限制條件:hasQueuedPredecessors()。
再進入 hasQueuedPredecessors(),可以看到該方法主要做一件事情:主要是判斷當前線程是否位于同步隊列中的第一個。如果是則返回 true,否則返回 false。
綜上,公平鎖就是通過同步隊列來實現多個線程按照申請鎖的順序來獲取鎖,從而實現公平的特性。非公平鎖加鎖時不考慮排隊等待問題,直接嘗試獲取鎖,所以存在后申請卻先獲得鎖的情況。
上述內容就是Java 中怎么實現公平鎖與非公平鎖,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。