1. 程式人生 > 其它 >面試篇 —— 談談你對鎖的理解

面試篇 —— 談談你對鎖的理解

一、非公平鎖

非公平鎖是搶佔式的,有優先順序區分的執行緒爭奪鎖。
包括:
synchronized關鍵字
new ReentrantLock()預設建立的也是非公平鎖

二、公平鎖

公平鎖是先到先得的原則,排隊獲取。
new ReentrantLock(true)

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

三、可重入鎖(遞迴鎖)

可重入鎖也叫遞迴鎖,指的是同步方法內呼叫加鎖方法,只需要獲取最外層鎖即可暢通無阻,內部的其他鎖不再需要獲取,可直接訪問。這種設計可以極大的減少鎖控制(如果是可重入鎖,只需要控制最外層的鎖即可),避免鎖控制混亂或釋放不及時導致死鎖發生的概率。

public synchronized void me01() {
	me02();
}

public synchronized void me02() { }

四、自旋鎖

自旋鎖是通過CAS原則,不停的比對以達到阻塞效果,比對成功後繼續執行程式已達到釋放鎖的效果。這樣不停迴圈比對的過程需要消耗系統資源。

    private volatile AtomicReference<Thread> thread = new AtomicReference<>();
    // 自旋加鎖,如果當前原子包裝執行緒物件是null就更新為當前物件
    public void locak() {
        while (!thread.compareAndSet(null, Thread.currentThread())) {}
    }
    public void getResource() {
        // 獲得鎖之後,其他執行緒再次呼叫該方法,通過比對不一致則一直空迴圈比對
        locak();
        // 執行邏輯
        
        // 釋放鎖,恢復為null,其他執行緒可以取鎖
        unLock();
    }
    // 釋放鎖,
    public void unLock() {
        while (!thread.compareAndSet(Thread.currentThread(), null)) {}

五、讀寫鎖

不管是synchronized還是ReentrantLock都是隻允許一個執行緒對資源進行讀和寫操作,這樣的效率是極低的。最理想的狀態是可以由多個執行緒讀的過程中限制只有一個執行緒的寫操作。核心是讀寫分離,舉個例子:
高鐵站候車室的多個顯示屏C端顯示著實時車次資訊,每個旅客相當於一個個執行緒讀,而候車資訊的更新只允許有許可權的某一個執行緒進行寫操作。

    Lock writeLock = new ReentrantReadWriteLock().writeLock();

    public void getResource() {
        // 獲取鎖
        writeLock.lock();
        try{
            // 原子業務邏輯
            
        } finally {
            // 釋放鎖
            writeLock.unlock();
        }
    }