Redisson 异步释放锁
在分布式系统中使用Redisson实现锁的问题。作者在尝试创建一个基础设施,让不同机器通过Redisson获取共享锁来执行异步任务
。在任务完成后,由于线程上下文的丢失,出现了尝试解锁失败的IllegalMonitorStateException
。为了解决这个问题,作者在获取锁时记录了线程ID,并在解锁时使用记录的线程ID来异步释放锁。此外,还展示了获取和释放锁的代码实现。
我正在尝试创建一个基础设施,不同的机器通过 Redisson 获取共享锁。一旦获得锁,一些异步任务就完成了,最后,当我完成工作时,我通过当前正在运行的线程释放 Redisson 锁 - 但我收到以下错误
java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: xxxxx thread-id: 57
所以,我明白那个意思,但是因为我要执行异步工作,所以我不能使用获取线程来执行释放。
我不应该使用 Redisson 锁吗?像这样的异步工作的最佳匹配是什么?
解决方案
:
由于需要异步解锁,所以上锁时,将线程Id也记录下来
@Override
public ResultIf<String> match(Long orderId) {log.info("ResourceServiceImpl.match input:{}", orderId);String requestId = "";RLock lock = null;try {// 获取登录用户信息ActiveUser activeUser = userSysDao.getCurrentUser();Assert.notNull(activeUser, "activeUser is null");Assert.isTrue(activeUser.getUid() != 0, "userId is null");// 尝试获取锁lock = RedisLock.tryFairlock(buildKey(MATCH_LOCK, orderId + "", activeUser.getUid() + ""));if (ObjectUtils.isEmpty(lock)) {return ResultIf.FAIL("请重试!");}boolean locked = lock.isLocked();if (locked) {return ResultIf.SUCCESS("正在匹配,请稍后重试");}requestId = IdUtil.randomId();Assert.isTrue(StringUtils.isNotEmpty(requestId), "requestId is null");boolean flag = lock.tryLock(60 * 4, TimeUnit.SECONDS);if (flag) {// 向redis中存入当前requestIdStringBuilder redisValue = new StringBuilder();redisValue.append(requestId);redisValue.append(":");redisValue.append(Thread.currentThread().getId());redisTemplateUtils.set(buildKey(MATCH_CURRENT_REQUEST, orderId + "", activeUser.getUid() + ""), redisValue.toString());// todo 业务代码return ResultIf.SUCCESS(requestId, "查询成功");}return ResultIf.SUCCESS("正在匹配,请稍后重试");} catch (Exception ex) {log.error("ResourceServiceImpl.match error", ex);return ResultIf.EXCEPTION(ex.getMessage());}
}
解锁
private void releaseLock(String orderId, String userId) {RLock lock = null;long threadId = 0l;try {/*** 2、释放分布式锁*/lock = RedisLock.tryFairlock(buildKey(MATCH_LOCK, orderId, userId));if (!ObjectUtils.isEmpty(lock)) {/*** 3、删除redis中当前requestId数据*/Object requestObj = redisTemplateUtils.get(buildKey(MATCH_CURRENT_REQUEST, orderId, userId));if (!ObjectUtils.isEmpty(requestObj)) {String redisValue = String.valueOf(requestObj);String[] split = redisValue.split(":");if (split.length == 2) {threadId = Long.valueOf(split[1]);}}// 是否还是锁定状态if (lock.isLocked()) {log.info("matchOperateLog unlock begin!");if (threadId != 0l) {lock.unlockAsync(threadId);boolean del = redisTemplateUtils.deleteKey(buildKey(MATCH_CURRENT_REQUEST, orderId, userId));log.info("matchOperateLog deleteKey remove res {}", del);} else {lock.unlockAsync();}log.info("matchOperateLog unlock end!");}}} catch (Exception e) {log.error("release operation failed", e);} finally {if (!ObjectUtils.isEmpty(lock) && lock.isLocked() && threadId != 0l) {lock.unlock();log.info("matchOperateLog finally unlock !");}}
}