多个线程访问共享资源这个时候为了线程的协调访问,需要使用分布式锁
线程在访问共享资源之前先需要获得一个令牌token 只有具有令牌的线程才可以访问共享资源,这个令牌才可以访问这个资源,分布式锁也是一个互斥资源,只有一个线程可以独占这个资源,其他线程只能等待,这个线程主动释放这个锁
如何确定一个分布式锁
独占性
高可用
防死锁 需要杜绝死锁 必须有超时中止机制
不乱抢 不能unlock别人的锁
重入性
在生产中,对于 Redisson 使用最多的场景就是其分布式锁 RLock。当然,RLock 仅仅是 Redisson 的线程同步方案之一。Redisson 提供了 8 种线程同步方案,用户可针对不同场景选 用不同方案。 需要注意的是,为了避免锁到期但业务逻辑没有执行完毕而引发的多个线程同时访问共 享资源的情况发生,Redisson 内部为锁提供了一个监控锁的看门狗 watch dog,其会在锁到 期前不断延长锁的到期时间,直到锁被主动释放。即会自动完成“锁续命”。
Redisson的分布式锁RLock是一种可重入锁,当一个线程获取到锁之后,这个线程可以再次获取本对象上面的锁,而其他的线程是不可以的
JDK当中的ReentrantLock和synchroized都是可重入锁
里面存在一个计数器,每进入一次自增1,每离开一次减1,到零则释放锁
Redisson 的可重入锁 RLock 默认是一种非公平锁,但也支持可重入公平锁 FailLock。当 有多个线程同时申请锁时,这些线程会进入到一个 FIFO 队列,只有队首元素才会获取到锁, 其它元素等待。只有当锁被释放后,才会再将锁分配给当前的队首元素
当一个线程需要同时处理多个共享资源时,可以使用联锁。即一次性申请多个锁,同时锁定多个共享资源,如果没有联锁的存在容易出现死锁问题,其实是操作系统中AND型信号量机制的典型应用
public String seckillHandler7() {
// 定义三个可重入锁
RLock rLock1 = redisson1.getLock(REDIS_LOCK + "-1");
RLock rLock2 = redisson2.getLock(REDIS_LOCK + "-2");
RLock rLock3 = redisson3.getLock(REDIS_LOCK + "-3");
// 定义联锁
RLock rLock = new RedissonMultiLock(rLock1, rLock2, rLock3);
其实联锁和红锁很像
一般用来解决Redis主从集群锁丢失问题
当master收到锁请求,没有来得及和slave 进行数据同步,master突然挂掉了
导致slave新选举的 master 里面不存在申请的锁,从而继续分配锁,导致共享资源的并行访问
原理:
红锁由多个锁组成 和联锁一样的 只有当这些锁当中的大部分锁申请成功时,红锁才能申请成功
public String seckillHandler7() {
// 定义三个可重入锁
RLock rLock1 = redisson1.getLock(REDIS_LOCK + "-1");
RLock rLock2 = redisson2.getLock(REDIS_LOCK + "-2");
RLock rLock3 = redisson3.getLock(REDIS_LOCK + "-3");
// 定义红锁
RLock rLock = new RedissonRedLock(rLock1, rLock2, rLock3);
红锁和联锁的区别是:
红锁实现的是对一个共享资源的访问
联锁实现的是对多个共享资源的访问
通过 Redisson 可以获取到读写锁 RReadWriteLock。通过 RReadWriteLock 实例可分别获 取到读锁 RedissonReadLock 与写锁 RedissonWriteLock。读锁与写锁分别是实现了 RLock 的可 重入锁。
一个共享资源,在没有写锁的情况下,允许同时添加多个读锁。只要添加了写锁,任何 读锁与写锁都不能再次添加。即读锁是共享锁,写锁为排他锁。
有点像操作系统里面的读写者问题,经典的资源同步访问问题
通过Redisson可以获取到信号量RSemaphore
应用场景有两种:
PermitExpirableSemaphore 该信号量是在 RSemaphore 基础上,为每个信号增加了一个过期时间,且每个信号都可以通过独立的 ID 来 辨识。释放时也只能通过提交该 ID 才能释放。
可过期信号量和信号量的不同,可过期的信号量一次只能申请一个,同时每个线程也只能释放一个,而信号量可以申请多个。
通过redisson.getPermitExpirableSemaphore( key )方法获取信号量,返回RPermitExpirableSemaphore。RPermitExpirableSemaphore调用会返回Sting对象也就是用于辨识的id,释放调用release( key )方法
通过Redisson的RCountDownLatch方法获得分布式闭锁,某线程需要等待其他线程完成之后,才进行操作,闭锁里面存放着一个计数器和阻塞队列,每有一个线程完成工作就会让计数器-1,直到减到0才会唤醒阻塞队列里面的所有线程。
条件线程和合并线程都需要 调用redisson的getCountDownLatch方法获取闭锁对象
latch.await方法阻塞合并线程,直到锁打开
latch.countDown方法使闭锁技术器-1