ReentrantLock源碼解析

1. 簡(jiǎn)介

  • ReentrantLocksynchronized關(guān)鍵字一樣是可重入的獨(dú)占鎖,不過(guò)ReentrantLock提供比synchronized關(guān)鍵字更加靈活的獲取鎖和釋放鎖操作,并且支持等待多個(gè)條件,但ReentrantLock必須手動(dòng)釋放鎖,否則很有可能造成死鎖。在JDK6之后,synchronized加入了偏向鎖、輕量級(jí)鎖、自適應(yīng)自旋、鎖粗化、鎖消除多種優(yōu)化措施使它的性能提高了很多,通常情況下表現(xiàn)一般比ReentrantLock好,所以在能使用synchronized功能完成的操作時(shí),盡量不要用ReentrantLock。

  • ReentrantLock中大部分方法是間接調(diào)用了AbstractQueuedSynchronizer的方法,所以要想進(jìn)一步探究其實(shí)現(xiàn)可以看看上一篇文章AbstractQueuedSynchronizer源碼解析

2. 實(shí)現(xiàn)

繼承關(guān)系

ReentrantLock實(shí)現(xiàn)了Lock接口

public class ReentrantLock implements Lock, java.io.Serializable {}

Lock接口提供了鎖最基本的幾個(gè)方法,實(shí)現(xiàn)該接口的類(lèi)都重寫(xiě)了這些方法

public interface Lock {
    // 阻塞獲取鎖
    void lock();
    // 阻塞獲取鎖,可響應(yīng)中斷拋出異常
    void lockInterruptibly() throws InterruptedException;
    // 嘗試獲取鎖
    boolean tryLock();
    // 嘗試在指定時(shí)間內(nèi)獲取鎖,獲取不到則阻塞直到獲取到鎖返回true或超時(shí)返回false
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    // 釋放鎖
    void unlock();
    // 創(chuàng)建一個(gè)等待條件,獲取鎖的線程可以等待條件
    Condition newCondition();
}

屬性

ReentrantLock中最重要的屬性就是sync,sync是個(gè)實(shí)現(xiàn)抽象隊(duì)列同步器AbstractQueuedSynchronizer抽象方法tryAcquiretryRelease的類(lèi)的對(duì)象,其中tryAcquire方法決定了是否公平、重入的特性,而tryRelease方法對(duì)公平與非公平重入鎖都適用。ReentrantLock中方法的實(shí)現(xiàn)基本都是調(diào)用sync的方法。

private final Sync sync;
Sync類(lèi)繼承關(guān)系

Sync

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

    // 添加抽象方法lock
    abstract void lock();

    // 添加非公平獲取嘗試同步狀態(tài)的方法,該方法體現(xiàn)非公平性與重入特性
    final boolean nonfairTryAcquire(int acquires) {
        // 獲取當(dāng)前線程
        final Thread current = Thread.currentThread();
        // 獲取當(dāng)前同步狀態(tài)
        int c = getState();
        // 如果沒(méi)有線程獲取同步狀態(tài)
        if (c == 0) {
            // 使用CAS方法獲取同步狀態(tài),這里體現(xiàn)非公平性,因?yàn)闆](méi)有判斷等待隊(duì)列里是否有其他線程在等待獲取同步狀態(tài)
            if (compareAndSetState(0, acquires)) {
                // 獲取成功則設(shè)置獨(dú)占線程
                setExclusiveOwnerThread(current);
                return true;
            }
        } // 否則當(dāng)前線程已經(jīng)獲取過(guò)同步狀態(tài)
        else if (current == getExclusiveOwnerThread()) {
            // 直接在原基礎(chǔ)狀態(tài)值加上acquires,體現(xiàn)重入性
            int nextc = c + acquires;
            // 如果nextc小于0表示線程獲取鎖的次數(shù)已經(jīng)超過(guò)最大值
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            // 設(shè)置新的同步狀態(tài)
            setState(nextc);
            return true;
        }
        return false;
    }

    // 重寫(xiě)tryRelease方法,對(duì)應(yīng)公平與非公平鎖都適用,體現(xiàn)重入性
    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;
    }

    // 判斷當(dāng)前線程是否獨(dú)占鎖
    protected final boolean isHeldExclusively() {
        // While we must in general read state before owner,
        // we don't need to do so to check if current thread is owner
        return getExclusiveOwnerThread() == Thread.currentThread();
    }

    // 創(chuàng)建等待條件
    final ConditionObject newCondition() {
        return new ConditionObject();
    }

    // 獲取獨(dú)占鎖的線程
    final Thread getOwner() {
        return getState() == 0 ? null : getExclusiveOwnerThread();
    }

    // 獲取當(dāng)前線程加鎖次數(shù)
    final int getHoldCount() {
        return isHeldExclusively() ? getState() : 0;
    }

    // 是否已加鎖
    final boolean isLocked() {
        return getState() != 0;
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

### NonfairSync

// 非公平鎖
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    final void lock() {
        // 如果當(dāng)前線程能直接獲取同步狀態(tài),則設(shè)置當(dāng)前線程為獨(dú)占線程
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else // 否則再調(diào)用acquire獲取同步狀態(tài)
            acquire(1);
    }

    // 重寫(xiě)tryAcquire方法,調(diào)用nonfairTryAcquire方法
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

FairSync

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    // 重寫(xiě)tryAcquire方法,該方法體現(xiàn)公平性與重入特性
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        // 如果還沒(méi)有線程獲取同步狀態(tài)
        if (c == 0) {
            // 判斷等待隊(duì)列中是否有后繼線程,沒(méi)有再使用CAS方法獲取同步狀態(tài),
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                // 獲取成功設(shè)置當(dāng)前線程為獨(dú)占線程
                setExclusiveOwnerThread(current);
                return true;
            }
        }  // 否則當(dāng)前線程已經(jīng)獲取過(guò)同步狀態(tài)
        else if (current == getExclusiveOwnerThread()) {
            // 直接在原基礎(chǔ)狀態(tài)值加上acquires,體現(xiàn)重入性
            int nextc = c + acquires;
            // 如果nextc小于0表示線程獲取鎖的次數(shù)已經(jīng)超過(guò)最大值
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            // 設(shè)置新的同步狀態(tài)
            setState(nextc);
            return true;
        }
        return false;
    }
}

構(gòu)造函數(shù)

// 默認(rèn)創(chuàng)建非公平鎖
public ReentrantLock() {
    sync = new NonfairSync();
}

// 根據(jù)指定參數(shù)創(chuàng)建公平或非公平鎖
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

獲取鎖方法

以下獲取鎖的方法都是調(diào)用Sync類(lèi)的方法或或從抽象隊(duì)列同步器繼承的方法

// 阻塞獲取鎖
public void lock() {
    sync.lock();
}

// 中斷獲取鎖
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

// 嘗試獲取鎖
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

// 超時(shí)獲取鎖
public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

釋放鎖方法

public void unlock() {
    sync.release(1);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ReentrantLock,可重入鎖,是一種遞歸無(wú)阻塞的同步機(jī)制。它可以等同于synchronized的使用,但是...
    FX_SKY閱讀 404評(píng)論 0 1
  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-03】 更新日志 前言 在java中,鎖是實(shí)現(xiàn)并發(fā)的關(guān)鍵組件,多個(gè)...
    一字馬胡閱讀 44,314評(píng)論 1 32
  • ReentrantLock簡(jiǎn)單使用demo如下: 注:獲取的鎖代碼要放到try塊之外,防止獲得鎖代碼異常,拋出異常...
    jijs閱讀 2,068評(píng)論 2 12
  • ReentrantLock 介紹 一個(gè)可重入的互斥鎖,它具有與使用{synchronized}方法和語(yǔ)句訪問(wèn)的隱式...
    tomas家的小撥浪鼓閱讀 4,253評(píng)論 1 4
  • 一、 概述 本文首先介紹Lock接口、ReentrantLock的類(lèi)層次結(jié)構(gòu)以及鎖功能模板類(lèi)AbstractQue...
    等一夏_81f7閱讀 1,135評(píng)論 0 0

友情鏈接更多精彩內(nèi)容