10.Redisson源码-CountDownLatch源码剖析

一、CountDownLatch基本原理

  1. countDownLatch最基本的原理其实就是,现在有4个客户端,分别是A、B、C、D,客户端A进行加锁后,设置三个线程来获取锁,那么,必须让接下来的三个客户端BCD都获取锁成功后,客户端A的逻辑才会继续向下走
  2. 如果说,指定3个客户端获取锁,获取锁的客户端数量没有到达3的话,客户端A是不会逻辑是不会向下走的,会被阻塞住

源码

代码片段一、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");
        // 这里会设置几个客户端来获取锁成功的数量,代码片段二、
        latch.trySetCount(3);
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]设置了必须有3个线程执行countDown,进入等待中。。。");

        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]在做一些操作,请耐心等待。。。。。。");
                        Thread.sleep(3000);
                        RCountDownLatch localLatch = redisson.getCountDownLatch("anyCountDownLatch”);
                        // 代码片段三、
                        localLatch.countDown();
                        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]执行countDown操作");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

        // 代码片段四、
        latch.await();
        System.out.println(new Date() + ":线程[" + Thread.currentThread().getName() + "]收到通知,有3个线程都执行了countDown操作,可以继续往下走");

    }

代码片段二、RedissonCountDownLatch

  1. 参数:
    KEYS[1]= “anyCountDownLatch”
    ARGV[2] = 3,其实就是count参数的值
@Override
public boolean trySetCount(long count) {
    // 这里设置的客户端获取锁的个数为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进来不存在,
            // 进入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

参数
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 ,其实就是anyCountDownLatch这KEY对应的值,
                    // 第一次是3,减去1,变成2,
                    // 这样的话,后面还允许2个客户端获取锁
                    "local v = redis.call('decr', KEYS[1]);” +
                    //1.如果v,第一次执行后为2小于等于0的话,就直接删除key,所以可以看到,
                    // 当执行到第三个客户端的时候,这里才会成立
                    "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);

        // 这里就是说,如果我们业务逻辑里设置的成功获取锁的客户端为3,如果三个客户端都已经成功获取锁,
        //那么KEY就不存在了,如代码片段三中的分析,而如果获取锁的客户端没有达到3的话,这里其实就会进入到一个死循环
        // 不停的等待,直到KEY的值为0,参会继续走下面的逻辑,否则就会一直阻塞在这里
        while (getCount() > 0) {
            // waiting for open state
            RedissonCountDownLatchEntry entry = getEntry();
            if (entry != null) {
                entry.getLatch().await();
            }
        }
    } finally {
        unsubscribe(future);
    }
}

三、demo执行结果图

  1. 刚开始main线程设置必须有三个线程/客户端执行countDown,也就是获取锁成功
  2. 接下来三个线程/客户端成功的获取了锁
  3. 最后三个线程获取锁执行,执行countDown逻辑后,主线程才会继续执行,否则就会一直阻塞住
CountDownLatch.png

四、总结

  1. 到此为止,Redisson的源码基本上已经分析差不多了,其实还有一些环境没有发出来,因为一篇文章不想太长,所以后面会陆陆续续的把redisson源码的其他部分发出来
  2. 接下来就要分析zk的分布式锁了,其实对比Redis分布式锁和zk的分布式锁的优缺点,全方面的进行对比之后,在我们的实际业务开发中,我们才会知道,到底哪个分布式锁更加适合我们,因为,没有最好,只有最合适。
  3. 大家一起努力,加油。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270