Java Concurrent ReentrantLock(Java 10)

前言

Reentrant是一種可重入鎖前翎,是一種遞歸無阻塞的同步機制稚配。實現(xiàn)了和synchronized類似的同步策略。與synchronized配合使用的wait港华、notify药有、notifyall等函數(shù),由Codition負責提供苹丸,這個后續(xù)另外會說愤惰。

使用

1、在使用上與synchronized差異的是 實現(xiàn)lock接口的reentrant需要手動的去lock和release赘理,因為synchronized是JVM也就是Java語法層面實現(xiàn)的宦言,而Lock是JDK里面實現(xiàn)的。相對于sychronized來說商模,我們使用時要比synchronized更加嚴謹奠旺,因為忘記釋放鎖非常容易導致死鎖蜘澜。建議選擇在finally中進行鎖的釋放
2、lock實現(xiàn)的鎖粒度可以控制更加小
3响疚、Lock 實現(xiàn)能更支持更多高級的特性鄙信,比如說鎖超時等。
4忿晕、因為是JDK實現(xiàn)装诡,所以具有了更多特性的高級鎖比如說:read lock、write lock践盼,并且支持我們自定義特殊的鎖鸦采,這個雖然通常用不太到,但必要時是非常有用的咕幻。
demo:首先是使用synchronize渔伯,感受一下

class Test1 {
    private static volatile int condition = 0;
    private static final Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    while (!(condition == 1)) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("a executed by notify");
                }
            }
        });
        A.start();
        Thread.sleep(2000);
        condition = 1;
        synchronized (lock) {
            lock.notify();
        }
    }
}

然后是使用Lock

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Test2 {
        private static volatile int condition = 0;
        private static Lock lock = new ReentrantLock();
        private static Condition lockCondition = lock.newCondition();
        public static void main(String[] args) throws InterruptedException {
            Thread A = new Thread(new Runnable() {
                @Override
                public void run() {
                    lock.lock();
                    try {
                        while (!(condition == 1)) {
                            lockCondition.await();
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    } finally {
                        lock.unlock();
                    }
                    System.out.println("a executed by condition");
                }
            });
            A.start();
            Thread.sleep(2000);
            condition = 1;
            lock.lock();
            try {
                lockCondition.signal();
            } finally {
                lock.unlock();
            }
        }
}

原理

開始看源碼:
首先可以看到ReentrantLock實現(xiàn)了LockSerializable 接口,序列化不多說肄程,Lock定義了是現(xiàn)在JDK中鎖的規(guī)范锣吼,然后類中持有一個Sync對象,其中Sync是ReentrantLock的一個靜態(tài)內(nèi)部類蓝厌,這是整個ReentrantLock的基礎吐限,Sync繼承自AQS,換句話說AQS也就是ReentrantLock的實現(xiàn)基礎褂始。

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;
    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

然后往后看會得到另外幾個靜態(tài)內(nèi)部類:FairSync诸典、NonfairSync,他們均繼承自Sync
這兩個區(qū)別最大的操作是:
如果當前線程不是鎖的占有者,則NonfairSync并不判斷是否有等待隊列,直接使用CAS去進行鎖的占用;
如果當前線程不是鎖的占有者,則FairSync則會判斷當前是否有等待隊列,如果有則將自己加到等待隊列尾;
這其實就是公平鎖&非公平鎖的實現(xiàn)崎苗,默認非公平狐粱。
下面的代碼中,我加了幾行注釋胆数,大家注重關注下可重入及公平非公平是如何實現(xiàn)的肌蜻。

/**
 * Sync object for non-fair locks
 */
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

它這里使用的是Sync里面的實現(xiàn):

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;
    /**
     * Performs non-fair tryLock.  tryAcquire is implemented in
     * subclasses, but both need nonfair try for trylock method.
     */
    @ReservedStackAccess
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {//注意一下這里
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {//可重入的實現(xiàn)
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
}

然后是FairSync的實現(xiàn)

/**
 * Sync object for fair locks
 */
static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;
    /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    @ReservedStackAccess
    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()) {//可重入部分的實現(xiàn)
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

看到這里,大體已經(jīng)能猜到具體實現(xiàn)了必尼。ReentrantLock中維護著一個AQS蒋搜,然后競爭鎖的線程是在這里排隊的,然后通過對應的CAS操作進行鎖的爭用判莉。具體的實現(xiàn)參考AQS及CAS豆挽。
默認非公平:

/**
 * Creates an instance of {@code ReentrantLock}.
 * This is equivalent to using {@code ReentrantLock(false)}.
 */
public ReentrantLock() {
    sync = new NonfairSync();
}

可以很明顯的看到底層實現(xiàn)幾乎完全依賴于AQS,其實就是AQS包了一層罷了券盅。

public void lock() {
    sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
    sync.release(1);
}
public int getHoldCount() {
    return sync.getHoldCount();
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帮哈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锰镀,更是在濱河造成了極大的恐慌娘侍,老刑警劉巖咖刃,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異憾筏,居然都是意外死亡嚎杨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門氧腰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枫浙,“玉大人,你說我怎么就攤上這事容贝∽愿” “怎么了之景?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵斤富,是天一觀的道長。 經(jīng)常有香客問我锻狗,道長满力,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任轻纪,我火速辦了婚禮油额,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刻帚。我一直安慰自己潦嘶,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布崇众。 她就那樣靜靜地躺著掂僵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪顷歌。 梳的紋絲不亂的頭發(fā)上锰蓬,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音眯漩,去河邊找鬼芹扭。 笑死,一個胖子當著我的面吹牛赦抖,可吹牛的內(nèi)容都是我干的舱卡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼队萤,長吁一口氣:“原來是場噩夢啊……” “哼灼狰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浮禾,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤交胚,失蹤者是張志新(化名)和其女友劉穎份汗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝴簇,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡杯活,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了熬词。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旁钧。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖互拾,靈堂內(nèi)的尸體忽然破棺而出歪今,到底是詐尸還是另有隱情,我是刑警寧澤颜矿,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布寄猩,位于F島的核電站,受9級特大地震影響骑疆,放射性物質(zhì)發(fā)生泄漏田篇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一箍铭、第九天 我趴在偏房一處隱蔽的房頂上張望泊柬。 院中可真熱鬧,春花似錦诈火、人聲如沸兽赁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刀崖。三九已至,卻和暖如春教沾,著一層夾襖步出監(jiān)牢的瞬間蒲跨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工授翻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留或悲,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓堪唐,卻偏偏與公主長得像巡语,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淮菠,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容