redis分布式锁(redisson)

redis分布式锁api:redisson


    org.redisson
    redisson
    3.7.2

redisson多线程执行流程:

  redis分布式锁(redisson)_第1张图片

注意点说明:

  • 线程一获取锁必须加等待获取时间,持有锁时间:在等待时间内没有获取锁则失败,防止无限等待造成死锁,持有锁时间:防止程序异常后没有执行释放锁代码使得该锁一致有效,其他线程无法获取锁造成的死锁。
  • 持有锁时间必须大于获取锁后业务代码执行时间,防止业务代码还没有执行完成就把锁提前释放的异常,但是生产上难免因为网络等问题造成 业务代码还没有执行完锁的有效时间就到了的情况:针对这种情况redisson在线程获取锁成功后另外起了一个线程,在锁到期后判断业务代码没执行完就会延长锁的时间
  • 获取锁对象时,需要加入redisKey的锁对象标识,用于和其他业务的锁对象做区分,防止释放锁时把别人的锁释放掉
  • 线程1获取锁成功后,线程2会while循环,自旋等待获取锁知道线程1释放后获取成功
  • 生产上redis一般不是单机的,采用集群或者哨兵,场景:线程1获取锁成功后正在处理业务代码,如果此时master宕机,系统启用slave,锁是不是会丢失,造成其他线程在线程1没结束前就获取到了锁呢?解决:redisson中会把集群或者哨兵中的锁同步到每一个redis服务器中,防止这种情况的发生
  • 除了一般普通的锁之外,redisson中还提供了读写锁,用来解决多读,少写的情况:场景:N个线程在读取资源,1个线程去修改,修改了一半发生了回滚,N个读线程会不会读取到修改了一般又回滚的脏数据呢,此时1个写线程可以加写锁,N个读线程可以加读锁,获取写锁后所有的读锁会进入自旋等待,直到读锁主动或回滚释放后,读锁才能获继续读取资源。所有的读锁是共享锁,不会互斥,所以多个读线程不会有锁等待,不会影响效率。
  • redisson底层采用的是LUA脚本来确保redis操作的原子性

具体使用:

@Autowired
@Lazy
private RedissonClient redissonClient;

public void lockTest() {
   // 生成redisKey常量
   String redisKey = "{redisPrefix}:" + "锁的唯一标识(业务字段)";
   // 由redisKey获取分布式锁对象
   RLock lock = redissonClient.getLock(redisKey);
   try {
     // 获取锁
     // 参数1:获取锁等待的时间,参数2:持有锁的时间,参数3:时间单位,返回值:是否获取成功  
     boolean lockResult = lock.tryLock("5", "10",TimeUnit.SECONDS); 
   } catch (Exception e) {
     // 获取锁过程中的异常处理
     log.error("获取锁异常,redisKey:{},异常信息:{}",redisKey,e);
     throw new serviceException("错误码");
   }
   // 判断是否获取成功
   if (!lockResult) {
     log.error("获取锁超时或失败,redisKey:{},异常信息:{}",redisKey,e);
     throw new serviceException("错误码")
   }
   // 开始执行业务代码,这里的代码越少越好
   try {
   } catch (Exception e) {
     log.error("处理业务异常代码失败,{}",e)
     thorw new serviceException("错误码")
   } finally {
     // 释放锁:必须判断是否是自己的锁,防止把别人的锁释放掉
     lock.unlock();
   }
}

 

你可能感兴趣的:(redis)