天天看點

(五)JDK鎖源碼分析之可重入鎖ReentrantLock

  • 概述

    什麼叫可重入鎖,簡而言之就是同一個線程可以多次擷取鎖而不被阻塞

  • 使用舉例
public static void main(String[] args) {

        for(int i=0;i<2;i++){
            new Thread(new TestLock()).start();
        }

        System.out.println("建立線程完成");
        //new Thread(new TestLock()).start();
    }

    private static class TestLock implements Runnable{

        private static int a=0;

        private static ReentrantLock reentrantLock = new ReentrantLock();

        @Override
        public void run() {
            reentrantLock.lock();
            a++;
            try {
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName()+"-a="+a);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reentrantLock.unlock();
        }
    }
           

這段代碼,執行的結果 會輸出一個 a=1 和 a=2(代碼可能不太嚴謹), 程式起了兩個線程,因為使用了鎖,是以a的值不會出現覆寫問題,會一個個線程排隊去執行.

  • ReentrantLock構造
    (五)JDK鎖源碼分析之可重入鎖ReentrantLock

    我們看到這個構造,可能會看到比較奇怪, 裡面直接給一個sync的變量指派, 其實ReentrantLock就是一個代理而已,在調用lock方法,其實使用的真正lock方法是調用sync的,在

    ReentrantLock内部有兩種實作如下:

    (五)JDK鎖源碼分析之可重入鎖ReentrantLock
    (五)JDK鎖源碼分析之可重入鎖ReentrantLock
    我們可以看到,兩個内部實作,都實作了lock方法,這個才是真正代理背後去擷取鎖的實作方法.

-lock方法(非公平方式)

(五)JDK鎖源碼分析之可重入鎖ReentrantLock

在lock方法中首先通過原子操作去擷取鎖, 被鎖定的狀态下值大于0,沒被鎖定情況下狀态中為1, 如果擷取到鎖,那麼就會把目前線程設定為鎖持有的線程, 如果沒有擷取到鎖,那麼調用acquire方法進行等待,那麼是怎麼等待的呢?

(五)JDK鎖源碼分析之可重入鎖ReentrantLock

acquire其實是父類(AbstractQueuedSynchronizer 同步器)的一個模版方法,具體怎麼去實作,根據鎖的特性去實作,acquire方法隻是作為一個主流程算法的一個控制,我們看看主流程

1.調用tryAcquire方法去嘗試擷取鎖, 同一個線程可以多次獲得鎖

(五)JDK鎖源碼分析之可重入鎖ReentrantLock

2.首先調用addWaiter方法使用尾插法将任務加入到隊列,然後方法acquireQueued使用cas算法去輪訓擷取鎖,阻塞目前線程

(五)JDK鎖源碼分析之可重入鎖ReentrantLock
(五)JDK鎖源碼分析之可重入鎖ReentrantLock
(五)JDK鎖源碼分析之可重入鎖ReentrantLock
  • unlock方法

    unlock方法原理很簡單,就是直接去釋放鎖,也就是把目前狀态值進行一個減少,減到0就表示目前線程已經釋放鎖,這個釋放鎖是不需要做線程安全的, 因為重入鎖是一種獨占鎖,在沒釋放前提下,其他線程都是被阻塞的,是以釋放鎖操作會簡單許多,隻是狀态值進行減小

    (五)JDK鎖源碼分析之可重入鎖ReentrantLock
    (五)JDK鎖源碼分析之可重入鎖ReentrantLock
    (五)JDK鎖源碼分析之可重入鎖ReentrantLock
    直接将狀态值減少,這是重入鎖的特性,狀态值會大于1,有個線程可以重複擷取鎖

繼續閱讀