Fork me on GitHub
如果对您有帮助,麻烦您点赞留言吧~~~

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

posted @ 2019-05-09 17:06  jarjune  阅读(314)  评论(0编辑  收藏  举报