ReentrantLock源碼解析

簡介

ReentrantLock是一個可重入的獨享鎖,是平時常用的一個鎖,用法和實現(xiàn)都比較簡單,如下:

    private static ReentrantLock lock = new ReentrantLock();
    private static void testLock() {

        for (int i=0;i<100000;i++) {
            lock.lock();
            try {
                test++;
            } catch (Exception e) {
                System.out.println(e.getMessage());
            } finally {
                lock.unlock();
            }
        }
    }
    private static void testLock2() {

        for (int i=0;i<100000;i++) {
            if(lock.tryLock()) {
                try {
                    test++;
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    private static void testLock3() throws Exception {

        for (int i=0;i<100000;i++) {
            if(lock.tryLock(1, TimeUnit.MINUTES)) {
                try {
                    test++;
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                } finally {
                    lock.unlock();
                }
            }
        }
    }

還有ReentrantLock支持可重入。

ReentrantLock是基于aqs獨占模式實現(xiàn)的,
本文重點介紹下公平和非公平模式,和ReentrantLock實現(xiàn)原理。

同步器-Sync

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;


        abstract void lock();

        //ReentrantLock 默認是非公平模式,這里給出了非公平模式下的嘗試獲取鎖
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            // AbstractQueuedSynchronizer 的state常用于保存資源被占用狀態(tài),這里保存ReentrantLock鎖狀態(tài),=0表示現(xiàn)在鎖現(xiàn)在沒被占用
            int c = getState();
            if (c == 0) {
                // 設置成占用狀態(tài),返回true,并設置lock擁有線程為當前線程,支持可重入
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //如果鎖已被占用,看是否是當前線程,如果是,可重入
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        // 實現(xiàn)tryRelease,嘗試釋放鎖,
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
        ```
    }

了解AbstractQueuedSynchronizer 都知道,AbstractQueuedSynchronizer暴露tryAcquire,tryRelease讓實現(xiàn)者自己去實現(xiàn),ReentrantLock的Sync實現(xiàn)了這兩個方法,用于判斷是否可以獲取鎖和釋放鎖,接下來介紹非公平模式和公平模式

非公平模式-NonfairSync

ReentrantLock支持公平、非公平兩種策略,并通過繼承AQS實現(xiàn)了對應兩種策略的同步器NonfairSync與FairSync,默認是非公平策略

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;


        // 這里實現(xiàn) lock方法,即ReentrantLock.lock方法
        final void lock() {
            // 這里判斷是否有其他資源占用,cas設置成功,說明當前線程獲取成功,這里
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                // 否則申請一個資源,就是這里會調用tryAcquire方法
                acquire(1);
        }
        
        //嘗試獲取鎖資源,調用的是非公平獲取鎖
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

公平模式-FairSync

    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        //獲取鎖
        final void lock() {
            acquire(1);
        }

        //公平模式和非公平模式區(qū)別就在這里,多了hasQueuedPredecessors判斷,就是看是否已有等待獲取鎖資源線程并且不是當前線程,如果有不去競爭
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

公平模式和非公平模式,區(qū)別就在于一個hasQueuedPredecessors函數(shù),該函數(shù)用于判斷是否已有節(jié)點在等待資源了并且不是該線程等待的,附上代碼

    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

以上就是公平模式和非公平模式實現(xiàn),都是實現(xiàn)了AbstractQueuedSynchronizer 的tryAcquire和tryRelease方法,用于判斷是否能夠獲取資源和釋放資源,實現(xiàn)簡單。

ReentrantLock的方法就不介紹了,都是調sync實現(xiàn)的方法,ReentrantLock最重要實現(xiàn)就是實現(xiàn)AbstractQueuedSynchronizer 的tryAcquire和tryRelease方法,支持可重入,還有支持Condition等待通知實現(xiàn)。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容