一、 测试
@Autowired
private RedisLockHelper redisLockHelper;
private static final String LOCK ="lock:equipment";
// 14: 48执行
//@Scheduled(cron = "0 48 14 ? * *")
public void orderSync() {
long time = () + (10*1000);
//进行加锁操作
if ((LOCK, time)) {
("加锁");
}else {
("解锁");
(LOCK,time);
}
}
二、操作redis的工具类
package ;
import .slf4j.Slf4j;
import ;
import ;
import ;
/**
*
* @author wyg
*/
@Component
@Slf4j
public class RedisLockHelper {
@Autowired
private RedisTemplate redisTemplate;
/**
* 加锁
* @param target 唯一标志
* @param timeStamp 当前时间+超时时间 也就是时间戳
* @return
*/
public boolean lock(String target, long timeStamp){
// 如果键不存在则新增,存在则不改变已经有的值。
if(().setIfAbsent(target,timeStamp)){
return true;
}
// 判断锁超时 - 防止原来的操作异常,没有运行解锁操作 防止死锁
long currentLock = (long) ().get(target);
// 如果锁过期 currentLock不为空且小于当前时间
if(currentLock < ()){
// 获取上一个锁的时间value 对应getset,如果lock存在 设置给过来的值,并返回旧的值
long preLock = (long) ().getAndSet(target,timeStamp);
// 假设两个线程同时进来这里,因为key被占用了,而且锁过期了。获取的值currentLock=A(get取的旧的值肯定是一样的),两个线程的timeStamp都是B,key都是K.锁时间已经过期了。
// 而这里面的getAndSet一次只会一个执行,也就是一个执行之后,上一个的timeStamp已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。
if(preLock==currentLock){
// preLock不为空且preLock等于currentLock,也就是校验是不是上个对应的商品时间戳,也是防止并发
return true;
}
}
return false;
}
/**
* 解锁
* @param target
* @param timeStamp
*/
public void unlock(String target,long timeStamp){
try {
long currentValue = (long) ().get(target);
if( currentValue<=timeStamp){
// 删除锁状态
().getOperations().delete(target);
}
} catch (Exception e) {
("警报!警报!警报!解锁异常{}",e);
}
}
}
还有一种写法:
public boolean lock(String target) {
String uuid = ().toString();
// 如果键不存在则新增,存在则不改变已经有的值。设置超时时间(解决异常,解决绝宕机)
if (().setIfAbsent(target, uuid, 10, )) {
return true;
}
try {
long Lock = (long) ().get(target);
//业务代码
}catch (Exception e){
();
}finally {
//解决自己的锁自己释放
if((().get(target))){
(target);
}
}
//注:这里有个缺点,当执行代码的时间超过锁的过期时间,会导致锁被释放掉,或者导致永久失效,这是需要加线程延长锁的时间或者用redission框架
}
还有一种redission加锁
@Autowired
private RedissonClient redissonClient
/*
* 这里只演示可重入锁,其他锁详情请查看官方文档
*/
// 获取redisson锁对象
RLock lock = ("anyLock");
//(1) 最常见的使用方法
();
//(2) 加锁以后10秒钟自动解锁
// 无需调用unlock方法手动解锁
(10, );
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = (100, 10, );
if (res) {
try {
...
} finally {
();
}
}
// (3)Redisson同时还为分布式锁提供了异步执行的相关方法
();
(10, );
Future<Boolean> res = (100, 10, );
<dependency>
<groupId></groupId>
<artifactId>redisson</artifactId>
<version>3.13.3</version>
</dependency>