10.Redisson源碼-CountDownLatch源碼剖析

一慌烧、CountDownLatch基本原理

  1. countDownLatch最基本的原理其實(shí)就是逐抑,現(xiàn)在有4個(gè)客戶端鸠儿,分別是A、B厕氨、C进每、D,客戶端A進(jìn)行加鎖后,設(shè)置三個(gè)線程來(lái)獲取鎖命斧,那么田晚,必須讓接下來(lái)的三個(gè)客戶端BCD都獲取鎖成功后,客戶端A的邏輯才會(huì)繼續(xù)向下走
  2. 如果說(shuō)国葬,指定3個(gè)客戶端獲取鎖贤徒,獲取鎖的客戶端數(shù)量沒(méi)有到達(dá)3的話芹壕,客戶端A是不會(huì)邏輯是不會(huì)向下走的,會(huì)被阻塞住

源碼

代碼片段一接奈、demo

public static void main(String[] args) throws Exception {
        Config config = new Config();
        config.useClusterServers()
                .addNodeAddress("redis://192.168.0.107:7001")
                .addNodeAddress("redis://192.168.0.107:7002")
                .addNodeAddress("redis://192.168.0.110:7003")
                .addNodeAddress("redis://192.168.0.110:7004")
                .addNodeAddress("redis://192.168.0.111:7005")
                .addNodeAddress("redis://192.168.0.111:7006");

        final RedissonClient redisson = Redisson.create(config);

        RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
        // 這里會(huì)設(shè)置幾個(gè)客戶端來(lái)獲取鎖成功的數(shù)量,代碼片段二踢涌、
        latch.trySetCount(3);
        System.out.println(new Date() + ":線程[" + Thread.currentThread().getName() + "]設(shè)置了必須有3個(gè)線程執(zhí)行countDown,進(jìn)入等待中序宦。睁壁。。");

        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        System.out.println(new Date() + ":線程[" + Thread.currentThread().getName() + "]在做一些操作互捌,請(qǐng)耐心等待潘明。。秕噪。钳降。。腌巾。");
                        Thread.sleep(3000);
                        RCountDownLatch localLatch = redisson.getCountDownLatch("anyCountDownLatch”);
                        // 代碼片段三牲阁、
                        localLatch.countDown();
                        System.out.println(new Date() + ":線程[" + Thread.currentThread().getName() + "]執(zhí)行countDown操作");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

        // 代碼片段四、
        latch.await();
        System.out.println(new Date() + ":線程[" + Thread.currentThread().getName() + "]收到通知壤躲,有3個(gè)線程都執(zhí)行了countDown操作城菊,可以繼續(xù)往下走");

    }

代碼片段二、RedissonCountDownLatch

  1. 參數(shù):
    KEYS[1]= “anyCountDownLatch”
    ARGV[2] = 3,其實(shí)就是count參數(shù)的值
@Override
public boolean trySetCount(long count) {
    // 這里設(shè)置的客戶端獲取鎖的個(gè)數(shù)為3
    return get(trySetCountAsync(count));
}

// count = 3
@Override
public RFuture<Boolean> trySetCountAsync(long count) {
    return commandExecutor.evalWriteAsync(getName(), 
    LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
            //1.exists anyCountDownLatch 客戶端A進(jìn)來(lái)不存在碉克,
            // 進(jìn)入if邏輯
            "if redis.call('exists', KEYS[1]) == 0 then “
                //1.set anyCountDownLatch 3
                + "redis.call('set', KEYS[1], ARGV[2]); "
                + "redis.call('publish', KEYS[2], ARGV[1]); “   
                //1.返回1代表成功
                + "return 1 "
            + "else "
                + "return 0 "
            + "end",
            Arrays.<Object>asList(getName(), getChannelName()),
             newCountMessage, count);
}

代碼片段三凌唬、RedissonCountDownLatch

參數(shù)
KEYS[1] = “anyCountDownLatch”


@Override
public void countDown() {
    get(countDownAsync());
}


@Override
public RFuture<Void> countDownAsync() {
    return commandExecutor.evalWriteAsync(getName(), 
    LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                    //1.decr anyCountDownLatch ,其實(shí)就是anyCountDownLatch這KEY對(duì)應(yīng)的值,
                    // 第一次是3漏麦,減去1客税,變成2,
                    // 這樣的話撕贞,后面還允許2個(gè)客戶端獲取鎖
                    "local v = redis.call('decr', KEYS[1]);” +
                    //1.如果v更耻,第一次執(zhí)行后為2小于等于0的話,就直接刪除key捏膨,所以可以看到秧均,
                    // 當(dāng)執(zhí)行到第三個(gè)客戶端的時(shí)候,這里才會(huì)成立
                    "if v <= 0 then redis.call('del', KEYS[1]) end;" +
                    "if v == 0 then redis.call('publish', KEYS[2], ARGV[1]) end;",
                Arrays.<Object>asList(getName(), getChannelName()), zeroCountMessage);
}

代碼片段四号涯、RedissonCountDownLatch


public void await() throws InterruptedException {
    RFuture<RedissonCountDownLatchEntry> future = subscribe();
    try {
        commandExecutor.syncSubscription(future);

        // 這里就是說(shuō)目胡,如果我們業(yè)務(wù)邏輯里設(shè)置的成功獲取鎖的客戶端為3,如果三個(gè)客戶端都已經(jīng)成功獲取鎖链快,
        //那么KEY就不存在了,如代碼片段三中的分析誉己,而如果獲取鎖的客戶端沒(méi)有達(dá)到3的話,這里其實(shí)就會(huì)進(jìn)入到一個(gè)死循環(huán)
        // 不停的等待,直到KEY的值為0域蜗,參會(huì)繼續(xù)走下面的邏輯巨双,否則就會(huì)一直阻塞在這里
        while (getCount() > 0) {
            // waiting for open state
            RedissonCountDownLatchEntry entry = getEntry();
            if (entry != null) {
                entry.getLatch().await();
            }
        }
    } finally {
        unsubscribe(future);
    }
}

三噪猾、demo執(zhí)行結(jié)果圖

  1. 剛開(kāi)始main線程設(shè)置必須有三個(gè)線程/客戶端執(zhí)行countDown,也就是獲取鎖成功
  2. 接下來(lái)三個(gè)線程/客戶端成功的獲取了鎖
  3. 最后三個(gè)線程獲取鎖執(zhí)行,執(zhí)行countDown邏輯后筑累,主線程才會(huì)繼續(xù)執(zhí)行畏妖,否則就會(huì)一直阻塞住
CountDownLatch.png

四、總結(jié)

  1. 到此為止疼阔,Redisson的源碼基本上已經(jīng)分析差不多了戒劫,其實(shí)還有一些環(huán)境沒(méi)有發(fā)出來(lái),因?yàn)橐黄恼虏幌胩L(zhǎng)婆廊,所以后面會(huì)陸陸續(xù)續(xù)的把redisson源碼的其他部分發(fā)出來(lái)
  2. 接下來(lái)就要分析zk的分布式鎖了迅细,其實(shí)對(duì)比Redis分布式鎖和zk的分布式鎖的優(yōu)缺點(diǎn),全方面的進(jìn)行對(duì)比之后淘邻,在我們的實(shí)際業(yè)務(wù)開(kāi)發(fā)中茵典,我們才會(huì)知道,到底哪個(gè)分布式鎖更加適合我們宾舅,因?yàn)橥嘲ⅲ瑳](méi)有最好,只有最合適筹我。
  3. 大家一起努力扶平,加油。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蔬蕊,一起剝皮案震驚了整個(gè)濱河市结澄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岸夯,老刑警劉巖麻献,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異猜扮,居然都是意外死亡勉吻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)旅赢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)齿桃,“玉大人,你說(shuō)我怎么就攤上這事鲜漩≡雌” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵孕似,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我刮刑,道長(zhǎng)喉祭,這世上最難降的妖魔是什么养渴? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮泛烙,結(jié)果婚禮上理卑,老公的妹妹穿的比我還像新娘。我一直安慰自己蔽氨,他們只是感情好藐唠,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鹉究,像睡著了一般宇立。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上自赔,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天妈嘹,我揣著相機(jī)與錄音,去河邊找鬼绍妨。 笑死润脸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的他去。 我是一名探鬼主播毙驯,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼灾测!你這毒婦竟也來(lái)了尔苦?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤行施,失蹤者是張志新(化名)和其女友劉穎允坚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蛾号,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡稠项,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鲜结。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片展运。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖精刷,靈堂內(nèi)的尸體忽然破棺而出拗胜,到底是詐尸還是另有隱情,我是刑警寧澤怒允,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布埂软,位于F島的核電站,受9級(jí)特大地震影響纫事,放射性物質(zhì)發(fā)生泄漏勘畔。R本人自食惡果不足惜所灸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望炫七。 院中可真熱鬧爬立,春花似錦、人聲如沸万哪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奕巍。三九已至吟策,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伍绳,已是汗流浹背踊挠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冲杀,地道東北人效床。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像权谁,于是被迫代替她去往敵國(guó)和親剩檀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350