高并发代码设计(redis)-暂时把redis当作数据库使用

1.没有并发的场景

@RequestMapping("/test")
    public String deductStock() throws InterruptedException {
        int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
        if(stock > 0){
            // 如果库存大于0
            Integer realStock = stock - 1;
            stringRedisTemplate.opsForValue().set("stock" , realStock.toString());
            System.out.println("扣除成功,剩余:" + realStock);
        } else {
            System.out.println("扣除失败,不足");
        }
        return "success";
    }

2.存在并发的场景(加jvm级别的锁)-单点的时候可用

@RequestMapping("/test")
    public String deductStock() throws InterruptedException {
        synchronized (this){
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if(stock > 0){
                // 如果库存大于0
                Integer realStock = stock - 1;
                stringRedisTemplate.opsForValue().set("stock" , realStock.toString());
                System.out.println("扣除成功,剩余:" + realStock);
            } else {
                System.out.println("扣除失败,不足");
            }
            return "success";
        }
    }

3.存在并发的场景(在redis层面进行加锁-利用redis单线程内存模型)-集群的时候---基本可用

@RequestMapping("/test")
    public String deductStock() throws InterruptedException {
        // setnx(防止key重复被覆盖数据) ; try-finally释放锁(防止执行过程中异常导致死锁,不能防止宕机的场景) ;加过期时间、原子化 防止宕机(防止死锁);
        String lockkey = "lock";
        try {
            // 高版本可用
            // Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, "zmc", 30L, TimeUnit.SECONDS);

            // 不保证原子性
            Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, "zmc");
            stringRedisTemplate.expire(lockkey, 30, TimeUnit.SECONDS);
            if(!result){
                return "error";
            }
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if(stock > 0){
                // 如果库存大于0
                Integer realStock = stock - 1;
                stringRedisTemplate.opsForValue().set("stock" , realStock.toString());
                System.out.println("扣除成功,剩余:" + realStock);
            } else {
                System.out.println("扣除失败,不足");
            }

        } finally {
            stringRedisTemplate.delete(lockkey);
        }
        return "success";

    }

4.一般高并发的场景(失效时间设置不合理:锁失效了代码还没执行完毕,finally中的delete会干掉其他线程的锁,可能导致所有的锁永久失效)(有可能超时:代码每执行完就锁过期了)

@RequestMapping("/test")
    public String deductStock() throws InterruptedException {
        // setnx(防止key重复被覆盖数据) ; try-finally释放锁(防止执行过程中异常导致死锁,不能防止宕机的场景) ;加过期时间、原子化 防止宕机(防止死锁);
        String lockkey = "lock";
        // 用于:每个线程只释放自己的锁
        String clientId = UUID.randomUUID().toString();
        try {
            // 高版本可用
            // Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, "zmc", 30L, TimeUnit.SECONDS);
            // 不保证原子性
            Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockkey, "zmc");
            stringRedisTemplate.expire(lockkey, 30, TimeUnit.SECONDS);
            if(!result){
                return "error";
            }
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if(stock > 0){
                // 如果库存大于0
                Integer realStock = stock - 1;
                stringRedisTemplate.opsForValue().set("stock" , realStock.toString());
                System.out.println("扣除成功,剩余:" + realStock);
            } else {
                System.out.println("扣除失败,不足");
            }

        } finally {
            if(clientId.equals(stringRedisTemplate.opsForValue().get(lockkey))){
                stringRedisTemplate.delete(lockkey);
            }
        }
        return "success";

    }

 

5.锁的时间设置不合理,因为不可预料所以不可能设置合理,所以需要有一个机制-每到锁的过期时间三分之一的时间的时候,重新设置过期时间

使用redission

@RequestMapping("/test")
    public String deductStock() throws InterruptedException {
        // setnx(防止key重复被覆盖数据) ; try-finally释放锁(防止执行过程中异常导致死锁,不能防止宕机的场景) ;加过期时间、原子化 防止宕机(防止死锁);
        String lockkey = "lock";
        // 用于:每个线程只释放自己的锁
        String clientId = UUID.randomUUID().toString();
        RLock redissonLock = redisson.getLock(lockkey);
        try {
            redissonLock.lock(30, TimeUnit.SECONDS);
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            if(stock > 0){
                // 如果库存大于0
                Integer realStock = stock - 1;
                stringRedisTemplate.opsForValue().set("stock" , realStock.toString());
                System.out.println("扣除成功,剩余:" + realStock);
            } else {
                System.out.println("扣除失败,不足");
            }

        } finally {
            redissonLock.unlock();
        }
        return "success";

    }

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值