/**
* 例如:当前偏移量为1
* T1 读取偏移量1,更新为2,sleep 未获取分布式锁
* T2 读取便宜量1,更新为3,更新为3。
* <p>
* T1 notified 获取分布式锁,更新为2。
* <p>
* 影响:预期为3,实际为2.
* 所以这里使用Double Check
*/
public void refreshReadMsgOffset(UserDO userDO, long msgId) {
//下面是第一次更新remark如果用户没有保存remark偏移量,就直接保存
if (StringUtils.isEmpty(userDO.getRemark())) {
// new user
UserRemarkBO userRemarkBO = new UserRemarkBO();
userRemarkBO.setMsgOffsetId(msgId);
userDAO.updateRemark(userDO.getId(), JSON.toJSONString(userRemarkBO));
return;
}
//这些代码都是相对同一个用户来说的,假设传进来的userDO和msgId 的userDO都是同一个用户,msgId分别是2,3,因为前端传来的都是最新的消息偏移量,这两个线程分别为T1,T2 通过userDO.getRemark()查询到的是1,一个更新2,一个更新3,所以最终是要更新3的,如果是一个更新2,一个更新3,那么更新2的话应该也是3才对,T2所以等3更新完成之后,T1在重新获取以下最新的数据就是3,这样就避免不是最新的值,
UserRemarkBO userRemarkBO = JSON.parseObject(userDO.getRemark(), UserRemarkBO.class);
if (userRemarkBO.getMsgOffsetId() >= msgId) return;
String key = LockKeyConstants.UPDATE_MSG_OFFSET_PREFIX + userDO.getId();
Boolean locked = distributedLock.lock(key, 10, TimeUnit.SECONDS);
if (!locked) return;
try {
// double check
userDO = userDAO.getById(userDO.getId());
userRemarkBO = JSON.parseObject(userDO.getRemark(), UserRemarkBO.class);
if (userRemarkBO.getMsgOffsetId() >= msgId) return;
userRemarkBO.setMsgOffsetId(msgId);
userDAO.updateRemark(userDO.getId(), JSON.toJSONString(userRemarkBO));
} finally {
distributedLock.unlock(key);
}
}
社区更新聊天消息偏移量问题
最新推荐文章于 2025-09-11 23:50:21 发布