redis实现分布式锁
1、maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
2、代码
@GetMapping("redis")
public String redis(){
final String lock = "locked";
String uuid = UUID.randomUUID().toString();
Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(lock, uuid, 30, TimeUnit.SECONDS);
if (!locked){
return "没有拿到锁";
}
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("locked-schedule-pool-%d").daemon(false).build());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//开启定时器线程为指定的key延长,防止主线程的操作还未执行完,lock已经因为过期而删除
stringRedisTemplate.expire(lock,30, TimeUnit.SECONDS);
}
//执行周期一般为设置的过期时间的1/3
},10,10, TimeUnit.SECONDS);
try {
Integer product = Integer.parseInt(stringRedisTemplate.opsForValue().get("product"));
if (product>0){
product = product-1;
System.out.println("继续出售="+product);
stringRedisTemplate.opsForValue().set("product",product.toString());
}else{
System.out.println("卖完了");
}
}finally {
//执行完毕,释放定时器
executorService.shutdown();
//只能删除自己的锁
DefaultRedisScript defaultRedisScript = new DefaultRedisScript();
//执行lua脚本 保证原子性 (主要是防止判断的时候满足条件,在删除的时刻,刚好过期,导致删除其他线程设置的锁)
defaultRedisScript.setScriptText("if redis.call('get',KEYS[1]) == ARGV[1] then redis.call('del',KEYS[1]) end");
List<String> keys = new ArrayList<>();
keys.add(lock);
stringRedisTemplate.execute(defaultRedisScript, keys, uuid);
}
return "ok";
}

浙公网安备 33010602011771号