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