分布式锁Redission

Redisson 作为分布式锁

官方文档:https://github.com/redisson/redisson/wiki

引入依赖

<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.11.1</version> </dependency>

2.配置redission

@Configuration public class MyRedissonConfig { /** * 所有对 Redisson 的使用都是通过 RedissonClient * * @return * @throws IOException */ @Bean(destroyMethod = "shutdown") public RedissonClient redisson() throws IOException { // 1、创建配置 Config config = new Config(); // Redis url should start with redis:// or rediss:// config.useSingleServer().setAddress("redis://192.168.163.131:6379"); // 2、根据 Config 创建出 RedissonClient 实例 return Redisson.create(config); } }

3.测试

@Autowired RedissonClient redissonClient; @Test public void redission() { System.out.println(redissonClient); }

4.使用

@ResponseBody @GetMapping("/hello") public String hello() { // 1. 获取一把锁 RLock lock = redisson.getLock("my-lock"); // 2. 加锁, 阻塞式等待 lock.lock(); try { System.out.println("加锁成功,执行业务..."); Thread.sleep(15000); } catch (Exception e) { } finally { // 3. 解锁 假设解锁代码没有运行,Redisson 会出现死锁吗?(不会) System.out.println("释放锁"+Thread.currentThread().getId()); lock.unlock(); } return "hello"; }

假设解锁代码没有运行,Redisson 会出现死锁吗?

不会

锁的自动续期,如果业务时间很长,运行期间自动给锁续期 30 s,不用担心业务时间过长,锁自动过期被删掉;

加锁的业务只要运行完成,就不会给当前锁续期,即使不手动续期,默认也会在 30 s 后解锁

源码分析-Redission如何解决死锁

Ctrl+Alt查看方法实现

image-20211006120452959

这是一个加锁方法,不传过期时间

public void lock() { try { //这里过期时间自动赋值成-1 this.lock(-1L, (TimeUnit)null, false); } catch (InterruptedException var2) { throw new IllegalStateException(); } }

然后会调用 this.lock(-1L, (TimeUnit)null, false)方法

private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException { //得到线程ID long threadId = Thread.currentThread().getId(); //通过线程ID获取到锁 Long ttl = this.tryAcquire(leaseTime, unit, threadId); //如果没有获取到锁 if (ttl != null) { RFuture<RedissonLockEntry> future = this.subscribe(threadId); this.commandExecutor.syncSubscription(future); try { while(true) { ttl = this.tryAcquire(leaseTime, unit, threadId); if (ttl == null) { return; } if (ttl >= 0L) { try { this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS); } catch (InterruptedException var13) { if (interruptibly) { throw var13; } this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS); } } else if (interruptibly) { this.getEntry(threadId).getLatch().acquire(); } else { this.getEntry(threadId).getLatch().acquireUninterruptibly(); } } } finally { this.unsubscribe(future, threadId); } } }

获取锁方法

private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) { return (Long)this.get(this.tryAcquireAsync(leaseTime, unit, threadId)); }

里面又调用了tryAcquireAsync

private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) { //如果传了过期时间 if (leaseTime != -1L) { return this.tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG); } //没有传过期时间 else { RFuture<Long> ttlRemainingFuture = this.tryLockInnerAsync(this.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG); ttlRemainingFuture.onComplete((ttlRemaining, e) -> { if (e == null) { if (ttlRemaining == null) { this.scheduleExpirationRenewal(threadId); } } }); return ttlRemainingFuture; } }

有指定过期时间走tryLockInnerAsync方法,尝试用异步加锁

<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) { //先把时间转换成internalLockLeaseTime this.internalLockLeaseTime = unit.toMillis(leaseTime); //然后执行lua脚本 发给redis执行 return this.commandExecutor.evalWriteAsync(this.getName(), LongCodec.INSTANCE, command, "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('hincrby', KEYS[1], ARGV[2], 1); redis.call('pexpire', KEYS[1], ARGV[1]); return nil; end; return redis.call('pttl', KEYS[1]);", Collections.singletonList(this.getName()), new Object[]{this.internalLockLeaseTime, this.getLockName(threadId)}); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwyxsz.html