Redis分布式锁

前言:基于redis实现企业级实际生产中分布式锁的应用

	/**
	 * 基于redis的分布式锁
	 *
	 * @param key
	 * @param expireSec 秒
	 * @return
	 */
	public boolean getLock(String key, int expireSec) {
		long expireTs = System.currentTimeMillis() + expireSec * 1000;
		Boolean b = redisTemplate.opsForValue().setIfAbsent(key, "" + expireTs);
		if (Boolean.TRUE.equals(b)) {
			return true;
		}
		boolean flag = false;
		try {
			// 值不为空且还未到过期时间,则视为获取锁失败
			Object v = get(key);
			if (Objects.nonNull(v) && Long.parseLong(v.toString()) >= System.currentTimeMillis()) {
				return false;
			}
			Object oldValue = redisTemplate.opsForValue().getAndSet(key, "" + expireTs);
			if (Objects.isNull(oldValue)) {
				return true;
			}
			flag = oldValue.toString().equals(v.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return flag;
	}

代码解析:

redis实现分布式锁的核心逻辑setnx命令+对应key设置过期时间

setnx命令保证多客户端redis会保证当前操作原子性,即要么设置成功,要么设置失败,多个客户端操作相互独立。

例如,假设有两个客户端 A 和 B 几乎同时尝试使用 SETNX 命令设置同一个键 mylock

  • 如果客户端 A 的 SETNX mylock valueA 命令先执行,并且键 mylock 不存在,那么 A 的操作将成功,并返回 1
  • 在 A 的操作完成后,客户端 B 的 SETNX mylock valueB 命令执行时,由于 mylock 已经存在,B 的操作将失败,并返回 0

在这个过程中,Redis 保证:

  • A 和 B 的操作不会互相干扰,不会出现 A 操作设置了一半的值然后被 B 操作覆盖的情况。
  • 最终 mylock 键的状态是确定的,要么是 A 设置的 valueA,要么是原本就存在的值(如果 A 操作之前 mylock 就已经存在的话)。

 对key设置过期时间是为了防止过程出现异常,key一直存在导致死锁问题

代码逐行说明:

Boolean b = redisTemplate.opsForValue().setIfAbsent(key, "" + expireTs);

这个一步对应的redis中命令setnx,同时我们将key对应的value设置为过期时间,后面我们通过改时间判断key有没有过期。这样做好处是我们不需要额外进行设置过期时间这一步骤,避免设置过期时间这一步发生异常设置失败,这个key就没有过期时间了。

Object v = get(key);
if (Objects.nonNull(v) && Long.parseLong(v.toString()) >= System.currentTimeMillis()) {
	return false;
}

这一步判断锁的过期时间,没过期说明锁还在被占用,获取失败。


			Object oldValue = redisTemplate.opsForValue().getAndSet(key, "" + expireTs);
			if (Objects.isNull(oldValue)) {
				return true;
			}
			flag = oldValue.toString().equals(v.toString());

这一步核心是使用getset命令,这是一个原子性操作,获取值并设置新值。如果获取的值为null说明可以正常获取锁,否则我们将getset获取到的值与上面get获取的值比较,相等说明是第一次设置值正常获取锁,不相等说明存在并发情况,这次getset已经不是第一次设置的值了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码场小兵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值