Redis基础知识(学习笔记22--分布式锁 Redisson )
分布式锁是控制分布式系统间同步访问共享资源的一种方式,其可以保证共享资源在并发场景下的数据一致性。
1. 工作原理
当有多个线程要访问某一个共享资源(DBMS中的数据或Redis中的数据,或共享文件等)时,为了达到协调多个线程的同步访问,此时就需要使用分布式锁了。
为了达到同步访问的目的,规定:让这些线程在访问共享资源之前先要获得一个令牌token,只有具有令牌的线程才可以访问共享资源。这个令牌就是通过各种技术实现的分布式锁。而这个分布式锁是一种”互斥资源“,即只有一个。只要有线程抢到了锁,那么其它线程只能等待,直到锁被释放或等待超时。
2. Redisson
2.1 原理
Redisson 内部使用Lua脚本实现了对可重入锁的添加、重入、续约(续命)、释放。Redisson需要用户为锁指定一个key,但无需为锁指定过期时间,因为它有默认过期时间(当然,也可指定)。由于该锁具有“可重入”功能,所以Redisson会为该锁生成一个计数器,记录一个线程重入锁的次数。
2.2 网址
https://github.com/redisson/redisson
知识wiki
https://github.com/redisson/redisson/wiki/Table-of-Content
3. Redisson 常用锁
3.1 可重入锁
Redisson的分布式锁RLock是一种可重入锁。当一个线程获取到锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。
- JDK中的reentrantLock(entrant是进入者、新会员的意思,reentrant是 可重入、可重入的 的意思)是可重入锁,其是通过AQS(抽象对象同步器)实现的锁机制。
- synchronized也是可重入锁,其是通过监视器模式(本质是OS的互斥锁)实现的锁机制。
3.2 公平锁 Fair Lock
Redisson的可重入锁RLock默认是一种非公平锁,但也支持可重入公平锁 Fair Lock。当有多个线程同时申请锁时,这些线程会进入到一个FIFO队列,只有队首元素才会获取到锁,其它元素等待。只有当锁被释放后,才会再将锁分配给当前的队首元素。
3.3 联锁 MultiLock
Redisson 分布式锁可以实现联锁 MultiLock。当一个线程需要同时处理多个共享资源时,可使用联锁。即一次性申请多个锁,同时锁定多个共享资源。联锁可以预防死锁。相当于对共享资源的申请实现了原子性:要么都申请到,只要缺少一个资源,则将申请到的资源释放。其是OS底层原理中 AND 型信号量机制的典型应用。
3.4 红锁 RedLock
Redisson 分布式锁可以实现红锁 RedLock。红锁由多个锁(同时至少是向三个Redis集群申请的锁)构成,只有当这些锁中的大部分锁申请成功时,红锁才申请成功。红锁一般用于解决Redis主从集群锁丢失问题。
红锁和联锁的区别:红锁实现的是对同一个共享资源的同步访问控制,而联锁实现的是多个共享资源的同步访问控制。
3.5 读写锁 RReadWriteLock
通过Redisson可以获取到读写锁 RReadWriteLock。通过 RReadWriteLock 实例可分别获取到读锁 RedissonReadLock 和 写锁 RedissonWriteLock。读锁与写锁分别是实现了RLock的可重入锁。
一个共享资源,在没有写锁的情况下,允许同时添加多个读锁。只要添加了写锁,任何读锁与写锁都不可以再次添加。即读锁是共享资源,写锁是排他锁。
3.6 信号量 Semaphore
通过Redisson可以获取到信号量RSemaphore。RSemaphore的常用场景有两种:一种是,无论谁添加的锁,任何其它线程都可以解锁,就可以使用RSemaphore。另外,当一个线程需要一次申请多个资源时,可使用RSemaphore。RSemaphore是信号量机制的典型应用。
3.7 可过期性信号量 PermitExpirableSemaphore
通过Redisson可以获取到可过期信号量PermitExpirableSemaphore。该信号量是在RSemaphore基础上,为每个信号量增加了一个过期时间,且每个信号都可以通过独立的ID来辨识。释放时也只能通过提交该ID才能释放。
不过,一个线程每次只能申请一个信号量,当然每次也只会释放一个信号量。这是与RSemaphore不同的地方。
该信号量为互斥信号量时,其就等同于可重入锁。或者说,可重入锁就相当于信号量为1的可过期信号量。
可过期信号量与可重入锁的区别,可重入锁:相当于用户每次只能申请1个信号量,且只有一个用户可以申请成功。可过期信号量:用户每次只能申请1个信号量,但可以有多个用户申请成功。
3.8 闭锁 RCountDownLatch
通过Redisson 可以获取到分布式闭锁 RCountDownLatch,其与JDK的JUC中的闭锁CountDownLatch原理一样,用法类似。其常用于一个或多个线程的执行必须在其它某些任务执行完毕的场景。例如,大规模分布式并行计算中,最终的合并计算必须基于很多并行计算的运行完毕。
闭锁中定义了一个计数器和一个阻塞队列。阻塞队列中存放者待执行的线程(又称 合并线程)。每当一个并行任务执行完毕(又称 条件线程),计数器就减1.当计数器递减到0时就会唤醒阻塞队列中的所有线程。
如果不使用Redisson,那么通常使用Barrier队列解决该问题,而Barrier队列通常使用Zookeeprt实现。
学习笔记--参阅特别声明
1.【Redis视频从入门到高级】
【https://www.bilibili.com/video/BV1U24y1y7jF?p=11&vd_source=0e347fbc6c2b049143afaa5a15abfc1c】