package com.luo.spring_vue.controller;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author
*
* @desc ...
* * @date 2020-12-20 11:10:29
* * *String key A, int expireTime 30 *
* * currentTime 1030 *
* * valueStr 1030 *
* * true * -------- *
* * String key B, int expireTime 30 *
* * currentTime 2030 *
* * valueStr 2030 *
* * currentValue 2030 *
* * currentValue !=null 2030<3030 *
* * oldValue 2030 *
* * oldValue!=null oldValue.equals(currentValue) *
* * true * --------- *
* String key C, int expireTime 30 *
* * currentTime 3030 *
* * valueStr 3030 *
* * currentValue 3030 *
* * currentValue !=null 3030<2030(!) *
* * false *
*/
@RestController
public class RedisController {
@Resource
private RedisTemplate redisTemplate;
public boolean lock(String key, int expireTime) {
long currentTime = System.currentTimeMillis() + expireTime;
String valueStr = String.valueOf(currentTime);
if (redisTemplate.opsForValue().setIfAbsent(key, valueStr)) {
//对应redis原生setnx操作
//可以成功设置,也就是key不存在
return true; }
//判断锁超时 - 防止原来的操作异常,没有运行解锁操作 防止死锁
String currentValue = (String) redisTemplate.opsForValue().get(key);
//如果锁过期
if (currentValue !=null&&Long.parseLong(currentValue)<System.currentTimeMillis()) {
//获取上一个锁的时间value
String oldValue = (String) redisTemplate.opsForValue().getAndSet(key, valueStr);
//假设两个线程同时进来这里,因为key被占用了,而且锁过期了。获取的值currentValue=A(get取的旧的值肯定是一样
//的),两个线程的value都是B,key都是K.锁时间已经过期了。而这里面的getAndSet一次只会一个执行,也就是一个执行之
//后,上一个的value已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。
if (oldValue!=null&&oldValue.equals(currentValue)) {
//oldValue不为空且oldValue等于currentValue,也就是校验是不是上个对应的商品时间戳,也是防止并发
return true; }
}
return false;
}
public void unlock(String key, String value) {
try {
String currentValue = (String) redisTemplate.opsForValue().get(key);
if (currentValue!=null&¤tValue.equals(value)) {
redisTemplate.delete(key);
}
}
catch (Exception e) {
e.printStackTrace();
}
}}
Redis锁
最新推荐文章于 2024-07-24 18:30:28 发布