前情提要:在使用公司组件时发现redisUtil中的解锁并没有判断锁是否已经失效了,所以给组件补充了Redisson原子性加解锁,续租的方法。
Redisson加解锁,续租
加锁,并返回拥有者信息
public String getLockOwner(String key, Long expire) throws InterruptedException {
Assert.hasLength(key, "key required");
RLock lock = redissonClient.getLock(key);
String lockOwner = UUID.randomUUID().toString();
boolean isLocked = lock.tryLock(expire, TimeUnit.SECONDS);
if (isLocked) {
RMap<String, String> lockMap = redissonClient.getMap(key, StringCodec.INSTANCE);
if (isLocked) {
lockMap.clear();
lockMap.put("lockOwner", lockOwner);
return lockOwner;
}
}
return null;
}
Redisson分布式锁原子性删除锁
public void releaseLock(String key, String lockOwner) {
Assert.hasLength(key, "key required");
Assert.hasLength(lockOwner, "lockOwner required");
String luaScript = "if redis.call('hget', KEYS[1], 'lockOwner') == ARGV[1] then " +
"return redis.call('hdel', KEYS[1], 'lockOwner') " +
"else return 0 end";
RScript rScript = redissonClient.getScript(StringCodec.INSTANCE);
Object result = rScript.eval(
RScript.Mode.READ_WRITE,
luaScript,
RScript.ReturnType.INTEGER,
Collections.singletonList(key),
lockOwner
);
if (result instanceof Long && (Long) result == 0L) {
log.info("锁未找到或已失效,无需释放");
}
}
续租
public void renewLock(String key, String lockOwner, Long expire) {
Assert.hasLength(key, "key required");
Assert.hasLength(lockOwner, "lockOwner required");
String luaScript = "if redis.call('hget', KEYS[1], 'lockOwner') == ARGV[1] then " +
"return redis.call('expire', KEYS[1], ARGV[2]) " +
"else return 0 end";
RScript rScript = redissonClient.getScript(StringCodec.INSTANCE);
Object result = rScript.eval(
RScript.Mode.READ_WRITE,
luaScript,
RScript.ReturnType.INTEGER,
Collections.singletonList(key),
lockOwner,
expire.toString()
);
log.info("renewLock结果: {}, 键: {}", result, key);
}
用例
@Async()
public void handleEventData(FlightJobAdjustEvent eventData) throws InterruptedException {
String lockName = "wsbJobConflictLog_" + IdUtil.getSnowflakeNextIdStr();
String lockOwner;
final int maxRenewals = 3;
final AtomicInteger renewalCount = new AtomicInteger(0);
try {
lockOwner = redisUtil.getLockOwner(lockName, 60L);
if (ObjUtil.isNotEmpty(lockOwner)) {
try {
Future<?> future = Executors.newVirtualThreadPerTaskExecutor().submit(() -> {
try {
if (!Thread.currentThread().isInterrupted()) {
log.warn("任务被中断,停止续租:" + lockName);
return;
}
while (Thread.currentThread().isInterrupted() && renewalCount.incrementAndGet() <= maxRenewals) {
Thread.sleep(30000);
redisUtil.renewLock(lockName, lockOwner, 60L);
}
log.warn("达到最大续租次数,停止续租:" + lockName);
} catch (Exception e) {
log.error("续租锁失败:" + e.getMessage(), e);
}
});
log.debug("开始处理日志业务");
wsbJobConflictLogService.logBusiness(eventData);
if (ObjUtil.isNotEmpty(future)) {
log.debug("关闭续约");
future.cancel(true);
}
} finally {
redisUtil.releaseLock(lockName, lockOwner);
}
} else {
log.warn("正在加锁中:" + lockName);
}
} catch (Exception e) {
log.error("处理日志业务出错:" + e.getMessage(), e);
throw e;
}
}