基于springboot框架使用redis(redisson)作为分布式锁,从synchronized开始分析弊端并解决

案例:电商平台下订单修改商品的数量,数量值放在redis中

				int num=(Integer) redisUtils.get("product") - 1;
                boolean set = redisUtils.set("product", num);   //redisUtils是我封装的redisTemplet,效果是一样的
                if((Integer)redisUtils.get("product")>0){
                int num=(Integer) redisUtils.get("product") - 1;
                boolean set = redisUtils.set("product", num);
                System.out.println((set==true?"执行成功!":"执行失败!")+"商品的数量为"+num);
            }
            else{
                System.out.println("库存不足,操作失败");
            }

并发问题:你当前读取的数量,下一刻就不是这个值了

  • 方法:使用synchronized,改为同步执行 弊端:集群环境下不适用,比如你使用负载均衡,启动两个tomcat,无效
  • 优化:解决上面的弊端:使用redis作为分布式锁,redis中的setnx指令,在springboot中
  boolean flag=redisTemplate.opsForValue().setIfAbsent(“lock”, “lock”);

当flag为true时,执行我们的业务代码,执行完释放(删除)锁。为false时,表示锁被抢占了,返回错误信息,请稍后再试之类的。
弊端:程序中发生异常,导致锁没释放,造成死锁,会一直操作失败。

  • 优化:try、catch,最后finally放删除锁的代码,保证一定执行
    弊端:finally的弊端明显,退出jvm或者死机都会执行不了

  • 优化:给锁加过期时间,例如30秒钟,就算挂掉了也会把锁清除
    弊端:(锁失效)某些情况下,第一个线程30秒还没执行完这个方法,锁却被redis释放了,那么别的线程进来,执行到半路上,第一个线程执行完,删除锁,这样第二个线程锁被第一个线程给清掉了,这样就相当于于没加锁一样,还是会并发问题。

  • 优化:给锁加上唯一标识到value上,uuid或者userid什么的都行,删除之前判断这个标识,这样保证释放的是自己加的锁。
    弊端:做到上面已经算是比较完善了,中小型企业完全撑得住,但是上面并没有从根本上解决执行时间过长,锁失效的问题,加长过期时间?时间太长导致别的线程一直在外面等待,不太好吧!

  • 优化:锁续命,开一个定时任务,(或者让获得锁的线程开启一个守护线程)每10秒钟检查锁,如果10秒前后检查的锁是一样的,那么就说明这把锁10秒钟还没释放掉,把这把锁的过期时间重新设置为30s

解决的原理说完了,那么请出redisson,它已经做好了一切。

启动类加上:

  @Value("${redisson.addr}")
    private String redisAddr;

  @Bean
    public Redisson redisson(){
        //单机模式
        Config config=new Config();
        config.useSingleServer().setAddress(redisAddr).setDatabase(0);
        return (Redisson) Redisson.create(config);
    }

配置文件:

redisson.addr=redis://192.168.157.128:6379

controller层:

 @Autowired
    private Redisson redisson;

接口里面:

RLock lock = redisson.getLock("gkl");   //1
        try{
            lock.lock();    //2
            if((Integer)redisUtils.get("product")>0){
                int num=(Integer) redisUtils.get("product") - 1;
                boolean set = redisUtils.set("product", num);
                System.out.println((set==true?"执行成功!":"执行失败!")+"商品的数量为"+num);
            }
            else{
                System.out.println("库存不足,操作失败");
            }
        }
        finally {
            lock.unlock();   //3
        }

三行代码搞定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值