redis(单机模式)分布式锁的实现【已废弃】
问题起源:后台刷新token的时候,会有高并发问题。
即:A发起请求的时候,刷新token时,还未存入redis,此时B发起请求,问题就出现了。
由于Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,所以本次用redis来解决这个问题。
INCR key
为键 key 储存的数字值加上一。
如果键 key 不存在, 那么它的值会先被初始化为 0 , 然后再执行 INCR 命令。
伪代码
@RestController
public class Demo {
private String key = "demo";
class DemoThread extends Thread {
// 是否结束的标识
private boolean isFinished = false;
public void setFinished(boolean finished) {
this.isFinished = finished;
}
@Override
public void run() {
for(int i = 0; i < 6; i++) {
if(isFinished) {
System.out.println("4.已解锁");
break;
} else {
System.out.println("5.续命。。。" + i);
template.expire(key, 5, TimeUnit.SECONDS);
}
try {
System.out.println("每1秒判断一次是否执行完毕");
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@RequestMapping("/demo")
public void demo() {
Thread thread = new DemoThread();
Random r = new Random();
try{
long flag = template.opsForValue().increment(key, 1);
template.expire(key, 10, TimeUnit.SECONDS);
if(flag == 1) {
thread.start();
if(r.nextInt(10) == 1) {
System.out.println("1.执行缓慢");
Thread.sleep(5000);
} else {
System.out.println("2.获取锁");
}
} else {
System.out.println("3.未获取锁");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
((DemoThread) thread).setFinished(true);
template.opsForValue().increment(key, -1);
}
}
}
解释
非公平锁,不是按照FIFO(先进先出)的顺序执行。
- 为了防止死锁,增加了过期时间。
- 为了防止网络延迟,导致业务还未执行完成,锁就已经失效,所以加了线程监听是否执行完成,如果未完成则续期。
- 为了防止业务逻辑执行超时(一直未到finally),所以上述只for循环了6次。
2019-06-20
由于加锁过程没有保证原子性,已废弃此方法,正式项目已改用redisson
有三个字送给你,
一是“诚”,
二是“勤”,
三是“专”。
当你无比地想做成一件事,
愿意为它倾尽无数心血和努力时,
结果总不会太差。
一是“诚”,
二是“勤”,
三是“专”。
当你无比地想做成一件事,
愿意为它倾尽无数心血和努力时,
结果总不会太差。