Redisson分布式锁

文章介绍了Redisson的分布式锁机制,包括可重入锁、公平锁、红锁、联锁、读写锁、信号量、可过期信号量和分布式闭锁等,强调了它们在并发控制和资源协调中的作用,如防止死锁、确保线程安全和资源的有序访问。

多个线程访问共享资源这个时候为了线程的协调访问,需要使用分布式锁

线程在访问共享资源之前先需要获得一个令牌token 只有具有令牌的线程才可以访问共享资源,这个令牌才可以访问这个资源,分布式锁也是一个互斥资源,只有一个线程可以独占这个资源,其他线程只能等待,这个线程主动释放这个锁

如何确定一个分布式锁

独占性

高可用

防死锁        需要杜绝死锁 必须有超时中止机制

不乱抢        不能unlock别人的锁

重入性        

Redisson 中的锁

在生产中,对于 Redisson 使用最多的场景就是其分布式锁 RLock。当然,RLock 仅仅是 Redisson 的线程同步方案之一。Redisson 提供了 8 种线程同步方案,用户可针对不同场景选 用不同方案。 需要注意的是,为了避免锁到期但业务逻辑没有执行完毕而引发的多个线程同时访问共 享资源的情况发生,Redisson 内部为锁提供了一个监控锁的看门狗 watch dog,其会在锁到 期前不断延长锁的到期时间,直到锁被主动释放。即会自动完成“锁续命”。

  • 1. 可重入锁

Redisson的分布式锁RLock是一种可重入锁,当一个线程获取到锁之后,这个线程可以再次获取本对象上面的锁,而其他的线程是不可以的

JDK当中的ReentrantLock和synchroized都是可重入锁

里面存在一个计数器,每进入一次自增1,每离开一次减1,到零则释放锁

  • 2. 公平锁

Redisson 的可重入锁 RLock 默认是一种非公平锁,但也支持可重入公平锁 FailLock。当 有多个线程同时申请锁时,这些线程会进入到一个 FIFO 队列,只有队首元素才会获取到锁, 其它元素等待。只有当锁被释放后,才会再将锁分配给当前的队首元素

  • 3.  联锁

当一个线程需要同时处理多个共享资源时,可以使用联锁。即一次性申请多个锁,同时锁定多个共享资源,如果没有联锁的存在容易出现死锁问题,其实是操作系统中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);

其实联锁和红锁很像

  • 4. 红锁

一般用来解决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);

红锁和联锁的区别是:

红锁实现的是对一个共享资源的访问

联锁实现的是对多个共享资源的访问

  • 5. 读写锁

通过 Redisson 可以获取到读写锁 RReadWriteLock。通过 RReadWriteLock 实例可分别获 取到读锁 RedissonReadLock 与写锁 RedissonWriteLock。读锁与写锁分别是实现了 RLock 的可 重入锁。

一个共享资源,在没有写锁的情况下,允许同时添加多个读锁。只要添加了写锁,任何 读锁与写锁都不能再次添加。即读锁是共享锁,写锁为排他锁。

有点像操作系统里面的读写者问题,经典的资源同步访问问题

  • 6. 信号量

通过Redisson可以获取到信号量RSemaphore

应用场景有两种:

  1. 一种是无论谁添加的锁,任何其他线程都可以解锁,就可以使用RSemaphore
  2. 当一个线程需要一次申请多个资源时,可使用RSemaphore

  • 7. 可过期信号量

PermitExpirableSemaphore 该信号量是在 RSemaphore 基础上,为每个信号增加了一个过期时间,且每个信号都可以通过独立的 ID 来 辨识。释放时也只能通过提交该 ID 才能释放。

可过期信号量和信号量的不同,可过期的信号量一次只能申请一个,同时每个线程也只能释放一个,而信号量可以申请多个。

通过redisson.getPermitExpirableSemaphore( key )方法获取信号量,返回RPermitExpirableSemaphore。RPermitExpirableSemaphore调用会返回Sting对象也就是用于辨识的id,释放调用release( key )方法

  • 8. 分布式闭锁

通过Redisson的RCountDownLatch方法获得分布式闭锁,某线程需要等待其他线程完成之后,才进行操作,闭锁里面存放着一个计数器和阻塞队列,每有一个线程完成工作就会让计数器-1,直到减到0才会唤醒阻塞队列里面的所有线程。

条件线程和合并线程都需要 调用redisson的getCountDownLatch方法获取闭锁对象

latch.await方法阻塞合并线程,直到锁打开

latch.countDown方法使闭锁技术器-1

### Redisson 分布式锁使用教程及示例代码 Redisson 是一个用于 RedisJava 客户端,提供了多种分布式对象和工具,其中包括分布式锁。以下是 Redisson 实现分布式锁的详细信息和代码示例。 #### 1. 添加依赖 在使用 Redisson 前,需要在项目中添加 Maven 或 Gradle 依赖。 ```xml <!-- Maven --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.20.0</version> </dependency> ``` ```gradle // Gradle implementation 'org.redisson:redisson:3.20.0' ``` #### 2. 配置 Redisson 客户端 创建 Redisson 客户端实例,连接到 Redis 服务器。 ```java import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class RedissonConfig { public static RedissonClient getClient() { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); return Redisson.create(config); } } ``` #### 3. 使用分布式锁 Redisson 提供了多种类型的分布式锁,包括 `RLock`、`FairLock` 和 `RedLock` 等。以下是一个简单的分布式锁使用示例。 ##### 示例代码:基于 RLock 的分布式锁 ```java import org.redisson.api.RLock; import org.redisson.api.RedissonClient; public class DistributedLockExample { private static final RedissonClient redissonClient = RedissonConfig.getClient(); public static void main(String[] args) throws InterruptedException { String lockKey = "product:001"; RLock lock = redissonClient.getLock(lockKey); try { // 尝试获取锁,等待时间最长为 10 秒,锁持有时间为 30 秒 boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS); if (isLocked) { System.out.println("锁已获取,执行业务逻辑..."); // 模拟业务逻辑处理 Thread.sleep(5000); } else { System.out.println("未能获取锁!"); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); System.out.println("锁已释放!"); } } } } ``` #### 4. 公平锁(Fair Lock) 公平锁确保线程按照请求锁的顺序获取锁,避免饥饿问题。 ```java import org.redisson.api.RLock; import org.redisson.api.RedissonClient; public class FairLockExample { private static final RedissonClient redissonClient = RedissonConfig.getClient(); public static void main(String[] args) throws InterruptedException { String lockKey = "fair-lock"; RLock fairLock = redissonClient.getFairLock(lockKey); try { fairLock.lock(); System.out.println("公平锁已获取,执行业务逻辑..."); Thread.sleep(5000); } finally { fairLock.unlock(); System.out.println("公平锁已释放!"); } } } ``` #### 5. 红锁(RedLock) 红锁是一种更复杂的分布式锁实现,适用于跨多个 Redis 实例的场景。 ```java import org.redisson.RedissonRedLock; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; public class RedLockExample { private static final RedissonClient redissonClient1 = RedissonConfig.getClient(); private static final RedissonClient redissonClient2 = RedissonConfig.getClient(); public static void main(String[] args) throws InterruptedException { RLock lock1 = redissonClient1.getLock("red-lock"); RLock lock2 = redissonClient2.getLock("red-lock"); RedissonRedLock redLock = new RedissonRedLock(lock1, lock2); try { redLock.lock(); System.out.println("红锁已获取,执行业务逻辑..."); Thread.sleep(5000); } finally { redLock.unlock(); System.out.println("红锁已释放!"); } } } ``` ### 注意事项 - 在实际应用中,建议设置合理的锁等待时间和锁持有时间,以避免死锁或锁超时[^1]。 - 分布式锁的释放必须在 `finally` 块中进行,确保无论是否发生异常都能正确释放锁[^2]。 - 如果业务逻辑复杂且耗时较长,可以考虑使用可重入锁或尝试锁机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值