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";
    }

相关推荐