配置pom文件
配置Bean
@Bean
public DefaultRedisScript<Long> defaultRedisScript() {
DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>();
defaultRedisScript.setResultType(Long.class);
defaultRedisScript.setScriptText("if redis.call('get', KEYS[1]) == KEYS[2] then return redis.call('del', KEYS[1]) else return 0 end");
return defaultRedisScript;
}
写一个获取线程锁和解锁的工具类
@Slf4j
@Component
public class Lock {
@Autowired
private StringRedisTemplate redisTemplate;
public Boolean lockEnable(String key, long expire) {
//这是将当前线程的名字置为key的value值,表明该锁被谁拿到
String keyValue = Thread.currentThread().getName();
//1,这是StringRedisTemplate在set key的同时增加了过期时间,防止死锁。保证了原子性。
//2,setIfAbsent该方法如果该key不存在时候,设置值进去后,返回true;若是已经存在,则返回false;
Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, keyValue, expire, TimeUnit.SECONDS);
Long surplusTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
if (!aBoolean) {
log.info("该线程【{}】加锁失败,该key【{}】剩余过期时间【{}】秒", keyValue, key, surplusTime);
return false;
}
log.info("该线程【{}】加锁成功,该key【{}】剩余过期时间【{}】秒", keyValue, key, surplusTime);
return true;
}
@Autowired
private DefaultRedisScript<Long> redisScript;
public Boolean lockUnable(String key) {
String keyValue = Thread.currentThread().getName();
//key和value不一致时,返回:【0】
//key和value一致时,返回:【1】
Long execute = redisTemplate.execute(redisScript, Arrays.asList(key, keyValue));
if(execute != 1 ){
Boolean aBoolean = redisTemplate.hasKey(key);
Long surplusTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
log.info("该key【{}】解锁失败,是否存在【{}】,剩余过期时间【{}】秒", key, aBoolean, surplusTime);
return false;
}
log.info("该key【{}】解锁成功", key);
Boolean aBoolean = redisTemplate.hasKey(key);
log.info("该key是否存在【{}】",aBoolean);
return true;
}
}
在测试单元多线程调用
@Test
public void catchData() {
for (int i = 0; i <100; i++) {
Thread thread = new Thread(() -> {
threadTest();
});
thread.start();
thread.setName("thread" + i);
}
while (true){
}
}
void threadTest(){
Boolean aBoolean = lock.lockEnable("秒杀", 600);
if (!aBoolean) {
log.info("线程【{}】没有拿到锁,结束流程",Thread.currentThread().getName());
return;
}
log.info("线程【{}】更新数据成功",Thread.currentThread().getName());
/**
* 释放该条数据的锁
*/
Boolean aBoolean1 = lock.lockUnable("狄仁杰");
log.info("线程【{}】是否成功释放锁:【{}】",Thread.currentThread().getName(),aBoolean1);
}
运行看效果