DistributedLock icon indicating copy to clipboard operation
DistributedLock copied to clipboard

运行过程中异常中断,锁超时时使用getset会出现争抢

Open cwocwo opened this issue 7 years ago • 1 comments

if (isTimeExpired(currLockInfo.getExpires())) 运行过程中异常中断,redis中会有一条锁记录,当程序重新启动后,多个线程会争抢锁,导致锁异常。

LockInfo currLockInfo = LockInfo.fromString(currLockInfoJson);
			// 竞争条件只可能出现在锁超时的情况, 因为如果没有超时, 线程发现锁并不是被自己持有, 线程就不会去动value
			if (isTimeExpired(currLockInfo.getExpires())) {
				// 锁超时了
				LockInfo oldLockInfo = LockInfo.fromString(jedis.getSet(lockKey, newLockInfoJson));
				if (oldLockInfo != null && isTimeExpired(oldLockInfo.getExpires())) {
					// 成功获取到锁, 设置相关标识
					logger.debug("{} get lock(new), lockInfo: {}", Thread.currentThread().getName(), newLockInfoJson);
					locked = true;
					return true;
				}
			} else {
				// 锁未超时, 不会有竞争情况
				if (isHeldByCurrentThread(currLockInfo)) { // 当前线程持有
					// 成功获取到锁, 设置相关标识
					currLockInfo.setExpires(serverTimeMillis() + lockExpires + 1); // 设置新的锁超时时间
					currLockInfo.incCount();
					jedis.set(lockKey, currLockInfo.toString());
					logger.debug("{} get lock(inc), lockInfo: {}", Thread.currentThread().getName(), currLockInfo);
					locked = true;
					return true;
				}
			}

cwocwo avatar Jul 13 '17 06:07 cwocwo

过期的时候 getSet 会被最后一个执行的线程覆盖.很严重的错误.慎用

timandy avatar Nov 20 '17 08:11 timandy