不废话直接上代码,具体情况请看注释
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.TimeUnit;
@Slf4j
@SpringBootTest
class StudyApplicationTests {
@Autowired
private RedissonClient redissonClient;
@Test
public void testRLock() {
//需要加锁的key
String lock_key = "lock_key";
RLock rLock = redissonClient.getLock("lock_key");
boolean locked = false;
try {
// 1. 传递了锁的有效时间,并且不等于-1,则到期之后直接锁失效(因为redis会自动删除到期的这个key)
// 可能会出现,业务还没有处理完毕,还没有到达显式解锁的地步,锁就已经释放了,而且此时再去显式的释放锁会报异常[IllegalMonitorStateException]
// 2. 不传递锁的有效时间,或者直接传递-1的情形下,锁的过期时间默认会置为30秒,并且激活看门狗的机制
// 在默认情况下,看门狗会每隔10秒给这个key续期一次 也就是默认值/3 默认值可配
//等待3秒,能够加上锁就加,加不上就放弃
locked = rLock.tryLock(3, TimeUnit.SECONDS);
if (locked) {
log.info("{}:加锁成功,开始处理业务", lock_key);
//模拟处理业务逻辑10秒
TimeUnit.SECONDS.sleep(10);
log.info("{}:业务处理完毕", lock_key);
} else {
log.error("{}:未能成功获取到锁,无法处理此业务", lock_key);
}
} catch (InterruptedException e) {
log.error("{}:尝试加锁过程中出现异常", lock_key);
} finally {
//如果当前线程并没有获取到锁的情况下,直接解锁会有异常存在,安全起见,try catch
//可以根据上面的 locked 来判断是不是需要执行解锁,但是判断了之后,因为某些原因, 该key在redis中还是没了,也会有异常
//总之 执行unlock 在没有锁的情况下执行会 IllegalMonitorStateException,双重判断
if (locked) {
try {
rLock.unlock();
log.info("{}:成功释放锁", lock_key);
} catch (Exception e) {
log.error("锁释放失败:{},原因:{}", lock_key, e.getMessage());
}
}
}
}
}
下面分别测试 分别试试 传递时间和不传递时间的执行日志的过程
第一种 不传递时间
locked = rLock.tryLock(3, TimeUnit.SECONDS);
执行的日志输出
lock_key:加锁成功,开始处理业务
lock_key:业务处理完毕
lock_key:成功释放锁
第二种 传递时间,传递一个比业务逻辑长的时间
locked = rLock.tryLock(3, 15, TimeUnit.SECONDS);
执行的日志输出
lock_key:加锁成功,开始处理业务
lock_key:业务处理完毕
lock_key:成功释放锁
第三种 传递时间, 传递一个比业务逻辑短的时间
locked = rLock.tryLock(3, 5, TimeUnit.SECONDS);
执行的日志输出
lock_key:加锁成功,开始处理业务
lock_key:业务处理完毕
锁释放失败:lock_key,原因:attempt to unlock lock, not locked by current thread by node id: f33ca091-7909-49c5-aeec-afa701e3c5f1 thread-id: 1
结论:
如果很清楚自己的业务大约多长时间能执行结束的话,可以给一个明确的时间
如果不确定的话,就不要加key的有效期了
Redisson的看门狗帮我们处理这个问题,自动续期,然后我们记得显式解锁