
@Service public class baseBrandServiceImpl extends ServiceImplimplements baseBrandService { @Autowired private RedisTemplate redisTemplate; @Autowired private RedissonClient redissonClient; public void setNum0() { String value = (String)redisTemplate.opsForValue().get("num"); if(StringUtils.isEmpty(value)){ redisTemplate.opsForValue().set("num","1"); }else{ int num = Integer.parseInt(value); //对num加1操作然后放入redis当中 redisTemplate.opsForValue().set("num",String.valueOf(++num)); } } //@Override public synchronized void setNum01() { String value = (String)redisTemplate.opsForValue().get("num"); if(StringUtils.isEmpty(value)){ redisTemplate.opsForValue().set("num","1"); }else{ int num = Integer.parseInt(value); //对num加1操作然后放入redis当中 redisTemplate.opsForValue().set("num",String.valueOf(++num)); } } private void doBusiness() { String value = (String) redisTemplate.opsForValue().get("num"); if (StringUtils.isEmpty(value)) { redisTemplate.opsForValue().set("num", "1"); } else { int num = Integer.parseInt(value); //对num加1操作然后放入redis当中 redisTemplate.opsForValue().set("num", String.valueOf(++num)); } } //分布式锁 方案一 缺点:if逻辑中若抛了异常,无法释放锁 public void setNum1() { //如果往redis里面设置值成功代表获取到了锁 boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", "ok"); if(acquireLock){ //如果这里出现异常 锁无法释放 会一直占用 doBusiness(); //★执行完业务逻辑之后删除锁,否则其他线程拿不到释放后的锁了 redisTemplate.delete("lock"); }else{ //设置睡眠时间 SleepUtils.sleepMillis(50); //自旋 setNum(); } } //分布式锁 方案二 缺点:锁过期时间和业务处理时间不一致,导致删除其他线程的锁 public void setNum2() { //如果往redis里面设置值成功代表获取到了锁 到期之后自动释放锁 但是此时有可能会把其他线程的锁给删掉 boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", "ok",3, TimeUnit.SECONDS); if(acquireLock){ doBusiness(); //执行完业务逻辑之后删除锁 redisTemplate.delete("lock"); }else{ //设置睡眠时间 SleepUtils.sleepMillis(50); //自旋 setNum(); } } //分布式锁 方案三 缺点:删除锁的操作不具备原子性,不保证判断和删除所操作同时执行成功/失败(原子性) public void setNum3() { //加锁的值信息 String uuid = UUID.randomUUID().toString(); //如果往redis里面设置值成功代表获取到了锁 boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS); if(acquireLock){ doBusiness(); //删除之前判定是否为该线程的锁 存在的问题在于下面的判断和删除不具备原子性 String redisUuid = (String)redisTemplate.opsForValue().get("lock"); if(uuid.equals(redisUuid)){ //执行完业务逻辑之后删除锁 redisTemplate.delete("lock"); } }else{ //设置睡眠时间 SleepUtils.sleepMillis(50); //自旋 setNum(); } } //分布式锁 方案四 lua 缺点:集群下依旧有安全问题,拿不同线程的锁 public void setNum4() { //加锁的值信息 String uuid = UUID.randomUUID().toString(); //如果往redis里面设置值成功代表获取到了锁 boolean acquireLock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS); if(acquireLock){ doBusiness(); //定义一个lua脚本 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; DefaultRedisscript redisscript = new DefaultRedisscript<>(); //把上面的script代码放到redisscript对象中 redisscript.setscriptText(script); //设置执行脚本之后返回值是什么类型 redisscript.setResultType(Long.class); //准备执行lua脚本 redisTemplate.execute(redisscript, Arrays.asList("lock"),uuid); }else{ //设置睡眠时间 SleepUtils.sleepMillis(50); //自旋 setNum(); } } //redissonClient方式一 //@Override public void setNum11() { RLock lock = redissonClient.getLock("lock"); lock.lock(); doBusiness(); lock.unlock(); } //redissonClient方式二 //@Override public void setNum22() { RLock lock = redissonClient.getLock("lock"); //加锁以后3秒之后自动释放 无需调用unlock lock.lock(3, TimeUnit.SECONDS); doBusiness(); lock.unlock(); } //★★★最终方案:redissonClient方式三 @Override public void setNum() { RLock lock = redissonClient.getLock("lock"); try { boolean acquireLock = lock.tryLock(100, 3, TimeUnit.SECONDS); if(acquireLock){ doBusiness(); }else{ //设置睡眠时间 SleepUtils.sleepMillis(50); //自旋 setNum(); } } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }