• Redisson读写锁和分布式锁详解


    锁的介绍

    分布式锁是一种排他锁,在分布式情况下只有一个线程(一台机器)能够抢到锁。
    读写锁是一种互斥锁,里面分为读锁和写锁,读锁和读锁不互斥,读锁和写锁互斥,写锁和写锁也互斥。

    使用场景

    当系统的两个地方使用同一份数据的时候,并且不能同时使用时可以加一个读写锁进行阻塞,如刷新缓存的时候不允许使用缓存,使用的时候不允许刷新。
    分布式锁可以在多个线程(机器)同时使用同一资源时使用,比如启动初始化,多集群只要有一台机器初始化即可。

    案例测试

    现在模拟一种场景,项目启动时让一台机器去初始化缓存,其他机器不再重复刷新。此时可以通过分布式锁的lock.tryLock(); 进行尝试获取锁,若获取不到则说明其他机器正在刷新缓存,可以不处理,如果拿的到则加锁进行刷新,刷新完释放锁。
    而此时假设有多个定时任务需要使用缓存数据,为了保持刷新缓存和读取缓存不相互影响,可以加个读写锁来控制,此时使用wLock.lock();rLock.lock(); 进行加锁,达到阻塞的作用。

    tryLock()方法是尝试获取锁,返回一个true或者false,拿不到锁不进行阻塞。
    lock()方法是尝试获取锁,拿不到锁进行阻塞,等待锁的释放再尝试抢占锁。

    先看下测试代码

    public void testLock() throws InterruptedException {
            String lockKey = "INIT_CACHE_LOCK";
            Lock lock = rdfaDistributeLockFactory.getLock(lockKey);
    
            RReadWriteLock readWriteLock = readWriteLockUtil.getReadWriteLock();
            RLock rLock = readWriteLock.readLock();
            RLock wLock = readWriteLock.writeLock();
            log.info("说明:两个分布式锁之间只有一个写锁的起终,写锁的起终之间不能有其他写锁和读锁,同一线程任意读锁起终之间不能有其他写锁,但允许有其他读锁。注:读锁和写锁抢不到阻塞,分布式锁抢不到则不处理。");
            log.info("-------------------------------------------------------------------------分割线-------------------------------------------------------------------------");
            for (int i = 0; i < 10; i++) {
                TimeUnit.SECONDS.sleep(5);
                new Thread(() -> {
                    if (lock.tryLock()) {
                        log.info("当前线程:" + Thread.currentThread().getName() + "初始化程序抢到分布式锁------------------------------------------分布式锁-起");
                        try {
                            wLock.lock();
                            log.info("当前线程:" + Thread.currentThread().getName() + "初始化程序抢到写锁=============================================写锁-起");
                            TimeUnit.SECONDS.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            log.info("当前线程:" + Thread.currentThread().getName() + "初始化程序释放写锁============================================写锁-终");
                            wLock.unlock();
                            log.info("当前线程:" + Thread.currentThread().getName() + "初始化程序释放分布式锁锁---------------------------------------分布式锁-终");
                            lock.unlock();
                        }
                    } else {
                        log.info("当前线程:" + Thread.currentThread().getName() + "缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理");
                    }
                }).start();
                TimeUnit.SECONDS.sleep(1);
                new Thread(() -> {
                    try {
                        rLock.lock();
                        log.info("当前线程:" + Thread.currentThread().getName() + "定时任务抢到读锁**********************************************读锁-起");
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        log.info("当前线程:" + Thread.currentThread().getName() + "定时任务释放读锁**********************************************读锁-终");
                        rLock.unlock();
                    }
                }).start();
            }
            TimeUnit.SECONDS.sleep(15);
            log.info("-------------------------------------------------------------------------分割线-------------------------------------------------------------------------");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    执行结果如下

     说明:两个分布式锁之间只有一个写锁的起终,写锁的起终之间不能有其他写锁和读锁,同一线程任意读锁起终之间不能有其他写锁,但允许有其他读锁。注:读锁和写锁抢不到阻塞,分布式锁抢不到则不处理。
     -------------------------------------------------------------------------分割线-------------------------------------------------------------------------
     当前线程:Thread-66初始化程序抢到分布式锁----------------------------------------分布式锁-起
     当前线程:Thread-66初始化程序抢到写锁============================================写锁-起
     redisson unlock redlock:org.redisson.RedissonLock@1ead4a6c
     当前线程:Thread-68缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理
     当前线程:Thread-66初始化程序释放写锁============================================写锁-终
     当前线程:Thread-66初始化程序释放分布式锁锁--------------------------------------分布式锁-终
     redission lock unlocked sucess:uds-calculate:INIT_CACHE_LOCK
     当前线程:Thread-67定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-70初始化程序抢到分布式锁----------------------------------------分布式锁-起
     当前线程:Thread-71定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-67定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-71定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-69定时任务抢到读锁**********************************************读锁-起
     redisson unlock redlock:org.redisson.RedissonLock@1ead4a6c
     当前线程:Thread-72缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理
     当前线程:Thread-73定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-69定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-73定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-70初始化程序抢到写锁============================================写锁-起
     redisson unlock redlock:org.redisson.RedissonLock@1ead4a6c
     当前线程:Thread-74缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理
     redisson unlock redlock:org.redisson.RedissonLock@1ead4a6c
     当前线程:Thread-76缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理
     当前线程:Thread-70初始化程序释放写锁============================================写锁-终
     当前线程:Thread-70初始化程序释放分布式锁锁--------------------------------------分布式锁-终
     redission lock unlocked sucess:uds-calculate:INIT_CACHE_LOCK
     当前线程:Thread-75定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-75定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-77定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-78初始化程序抢到分布式锁----------------------------------------分布式锁-起
     当前线程:Thread-79定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-77定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-79定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-78初始化程序抢到写锁============================================写锁-起
     redisson unlock redlock:org.redisson.RedissonLock@1ead4a6c
     当前线程:Thread-80缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理
     redisson unlock redlock:org.redisson.RedissonLock@1ead4a6c
     当前线程:Thread-82缓存初始化正在进行中,当前机器不处理!^^^^^^^^^^^^^^^^^^^^^^^^^^未抢到分布式锁-不处理
     当前线程:Thread-78初始化程序释放写锁============================================写锁-终
     当前线程:Thread-78初始化程序释放分布式锁锁---------------------------------------分布式锁-终
     当前线程:Thread-81定时任务抢到读锁**********************************************读锁-起
     redission lock unlocked sucess:uds-calculate:INIT_CACHE_LOCK
     当前线程:Thread-81定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-83定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-84初始化程序抢到分布式锁-----------------------------------------分布式锁-起
     当前线程:Thread-85定时任务抢到读锁**********************************************读锁-起
     当前线程:Thread-83定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-85定时任务释放读锁**********************************************读锁-终
     当前线程:Thread-84初始化程序抢到写锁============================================写锁-起
     当前线程:Thread-84初始化程序释放写锁============================================写锁-终
     当前线程:Thread-84初始化程序释放分布式锁锁--------------------------------------分布式锁-终
     redission lock unlocked sucess:uds-calculate:INIT_CACHE_LOCK
     -------------------------------------------------------------------------分割线-------------------------------------------------------------------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    由以上测试案例可以看出分布式锁是排他锁,读写锁是互斥锁,且
    读-读不互斥
    读-写互斥
    写-写互斥

  • 相关阅读:
    java 前后端开发 常用下载链接
    手写Mybatis源码(原来真的很简单!!!)
    【玩物立志-scratch少儿编程】骑上小摩托(动态背景+摄像头控制操作)
    MySQL常用命令(DQL)
    oracle高级—用户操作
    LVS,Nginx,Haproxy三种负载均衡产品的对比
    WPF 单击移动窗口 MouseLeftButtonDown 事件
    Docker安装以及修改Docker的默认存储路径
    使用aqua data studio进行mysql、oracle、syabse等等debug调试
    【一文秒懂——SLF4j日志】
  • 原文地址:https://blog.csdn.net/qq_40359381/article/details/126558092