如何理解Java中的公平鎖和非公平鎖?

從字面意思理解,其實灰常簡單,公平就是大家買票都排隊,不公平就是有人開了超級VIP,插隊了。所以在多線程中,就存在公平鎖和非公平鎖,如何理解呢?

公平鎖:多個線程按照申請鎖的順序去獲得鎖,所有線程都在隊列裏排隊,這樣就保證了隊列中的第一個先得到鎖。

優點:所有的線程都能得到資源,不會餓死在隊列中。

缺點:吞吐量會下降很多,隊列裏面除了第一個線程,其他的線程都會阻塞,cpu喚醒阻塞線程的開銷會很大。

非公平鎖:多個線程不按照申請鎖的順序去獲得鎖,而是同時直接去嘗試獲取鎖(插隊),獲取不到(插隊失敗),再進入隊列等待(失敗則乖乖排隊),如果能獲取到(插隊成功),就直接獲取到鎖。

優點:可以減少CPU喚醒線程的開銷,整體的吞吐效率會高點,CPU也不必取喚醒所有線程,會減少喚起線程的數量。

缺點:可能導致隊列中排隊的線程一直獲取不到鎖或者長時間獲取不到鎖,活活餓死。

在Java多線程併發操作中,我們操作鎖大多時候都是基於Sync本身去實現的,而Sync本身卻是ReentrantLock本身的一個內部類,Sync本身又繼承AbstractQueuedSynchronizer,如圖:

那我們如何去實現一個公平鎖和非公平鎖呢?我們就以買票這個例子,通過ReentrantLock進行講解:

public class FairLocked implements Runnable {
	private int seatNumber = 100;
	/**
	 * 公平鎖實現 ReentrantLock構造方法中設置爲true:代表公平鎖
	 * 
	 * 設置爲false:代表非公平鎖 默認也是非公平鎖
	 * 
	 */
	/** private ReentrantLock lock = new ReentrantLock(true); */

	/** private ReentrantLock lock = new ReentrantLock(false); */
	private ReentrantLock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {
			try {
				lock.lock();
				if (seatNumber > 0) {
					Thread.sleep(100);
					--seatNumber;
					System.out.println(Thread.currentThread().getName() + "佔用1個座位,還剩餘 " + seatNumber + "個座位");
				} else {
					System.out.println(Thread.currentThread().getName() + ":不好意思,票賣完了!");
					break;
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {

				lock.unlock();
			}
		}
	}

	public static void main(String[] args) {
		FairLocked rlbr = new FairLocked();
		Thread t1 = new Thread(rlbr, "A窗口");
		Thread t2 = new Thread(rlbr, "B窗口");
		t1.start();
		t2.start();
	}
}

需要注意的是,默認情況下是非公平,想要公平鎖就得設置爲true,所以看上述的輸出就可以看出,A線程和B線程存在資源爭搶(插隊),這個就是非公平鎖,我們設置爲true看看是什麼效果:

可以看出,AB線程是非常有序的,就是進行排隊執行!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章