探究-redisson-直击面试

452 阅读2分钟

github官方中文文档

学习视频

可以干什么

分布式锁、分布式对象、分布式集合

防止死锁

设置可重入锁

配置redisson

// 默认连接地址 127.0.0.1:6379
RedissonClient redisson = Redisson.create();

Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);

简单使用redisson:Lock

今天没时间 写代码测试:先学习一下结论

大概看一下有那些redisson给我们提供了那些锁

image.png

基本都是我们Java中JUC中的Lock的类型

说实话 官方比我讲的好(哈哈哈)

可重入锁

说一下什么是死锁

以redis讲 :当一个线程获得了这把锁,执行业务服务代码。然后服务突然宕机,redis中存的key一直没销毁。第二线程试图去获取当前这把锁,发现那个key一直存在就一直在哪等待!

借助文旦

2022-7-29

实战开始

添加依赖

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson-spring-boot-starter</artifactId>
  <version>3.16.6</version>
</dependency>

加添配置

我本地reids

先结论

业务超长 自动续期
默认是30秒的过期时间
阻塞等待lock.lock(); 自动续期
lock.lock(11,TimeUnit.SECONDS); 没有看门狗自动续期

看门狗续期源码源码:

首先说为啥说:默认30秒(你在上锁的时候自动构造一个锁对象) 源码:挺深的

public RedissonBaseLock(CommandAsyncExecutor commandExecutor, String name) {
    super(commandExecutor, name);
    this.commandExecutor = commandExecutor;
    this.id = commandExecutor.getConnectionManager().getId();
    默认是30秒的过期时间
    this.internalLockLeaseTime = commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout();
    this.entryName = this.id + ":" + name;
}

public long getLockWatchdogTimeout() {
    return this.lockWatchdogTimeout;
}

public Config() {
    this.transportMode = TransportMode.NIO;
    // 这是上锁后默认 30秒
    this.lockWatchdogTimeout = 30000L;
    this.reliableTopicWatchdogTimeout = TimeUnit.MINUTES.toMillis(10L);
    this.keepPubSubOrder = true;
    this.useScriptCache = false;
    this.minCleanUpDelay = 5;
    this.maxCleanUpDelay = 1800;
    this.cleanUpKeysAmount = 100;
    this.nettyHook = new DefaultNettyHook();
    this.useThreadClassLoader = true;
    this.addressResolverGroupFactory = new DnsAddressResolverGroupFactory();
}

看门狗续期源码

private void renewExpiration() {
    RedissonBaseLock.ExpirationEntry ee = (RedissonBaseLock.ExpirationEntry)EXPIRATION_RENEWAL_MAP.get(this.getEntryName());
    if (ee != null) {
        Timeout task = this.commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
            public void run(Timeout timeout) throws Exception {
                RedissonBaseLock.ExpirationEntry ent = (RedissonBaseLock.ExpirationEntry)RedissonBaseLock.EXPIRATION_RENEWAL_MAP.get(RedissonBaseLock.this.getEntryName());
                if (ent != null) {
                    Long threadId = ent.getFirstThreadId();
                    if (threadId != null) {
                        RFuture<Boolean> future = RedissonBaseLock.this.renewExpirationAsync(threadId);
                        future.onComplete((res, e) -> {
                            if (e != null) {
                                RedissonBaseLock.log.error("Can't update lock " + RedissonBaseLock.this.getRawName() + " expiration", e);
                                RedissonBaseLock.EXPIRATION_RENEWAL_MAP.remove(RedissonBaseLock.this.getEntryName());
                            } else {
                                if (res) {
                                    RedissonBaseLock.this.renewExpiration();
                                } else {
                                    RedissonBaseLock.this.cancelExpirationRenewal((Long)null);
                                }

                            }
                        });
                    }
                }
            }
           internalLockLeaseTime - 这个成员变量:就是刚构造对象构造出来的30s
           怎么续期 30s/3s=10s  10秒自动续期
        }, this.internalLockLeaseTime / 3L, TimeUnit.MILLISECONDS);
        ee.setTimeout(task);
    }
}

记性不好了 学了忘 忘了学

lock.lock(11,TimeUnit.SECONDS); 说一下为什么没有看门狗自动续期

没有续期的代码  
<T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
    return this.evalWriteAsync(this.getRawName(), LongCodec.INSTANCE, command, "if (redis.call('exists', KEYS[1]) == 0) then redis.call('hincrby', 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.getRawName()), new Object[]{unit.toMillis(leaseTime), this.getLockName(threadId)});
}

读写锁

读锁随时可读,写锁悲观锁-独占锁

信号量:

就是限量 操作~~~ 控制好总量 其他请求过来拒绝或者是报错

闭锁

放假校门锁门:大一新生 走 大二走 大三走 大四走 学校才能锁门