zoukankan      html  css  js  c++  java
  • redis分布式锁的使用

    1.通过官方文档查看相关的命令操作:http://www.redis.cn/commands.html

      关键命令:setIfAbsent(String key,String value)对应官方文档的 setnx

           解释:将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。

          getAndSet

          解释:自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。(get旧值,set新值)

    2.编写redisLock,即上锁和解锁的方法:

    @Service
    @Slf4j
    public class RedisLock {
        @Autowired
        StringRedisTemplate template;
    
        public boolean lock(String key,String value){
            //1.如果能设置value表示锁没被占用,返回true表示上锁成功,否则进入下一步
            if (template.opsForValue().setIfAbsent(key,value)) {
                return true;
            }
            
            String currentValue = template.opsForValue().get(key);
            //2.这一步是为了防止死锁,因为如果被上锁的那段程序抛出异常,会导致无法执行解锁方法从而导致死锁
            //所以value的值应设为当前时间+超时时间,当Redis里的currentValue小于线程当前的系统时间,
            //说明死锁产生了,需解开这个死锁
            if(!StringUtils.isEmpty(currentValue)&&Long.valueOf(currentValue)<System.currentTimeMillis()) {
                //3.解死锁的操作,把原来的currentValue设置为新的value,并为拿到锁的新线程重新上锁
                String oldValue = template.opsForValue().getAndSet(key, value);
                //4.这步是为了防止在死锁产生的时候,同时有多个线程进来上锁
                // ,只有oldValue等于currentValue的线程才可成功上锁
                if(!StringUtils.isEmpty(oldValue)&&oldValue.equals(currentValue)) {
                    template.opsForValue().set(key,value);
                    return true;
                }
            }
            //上锁失败
            return false;
        }
    
        public void unlock(String key,String value){
            
            try {
                String currentValue = template.opsForValue().get(key);
                //只有在Redis里面的CurrentValue等于传进来的Value才能解锁
                if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                    template.delete(key);
                }
            }catch (Exception e){
                log.error("【redis分布式锁】解锁异常, {}", e);
            }
        }
    }

    3.在相应的程序里调用redisLock

     @Override
        public String orderSecKillProduct(String productId) {
            //value的值设为当前时间+超时时间
            String time=String.valueOf(System.currentTimeMillis()+10*1000);
            //加锁
            if(!redisLock.lock(productId,time)){
                //上锁失败,抛出异常跳转到相应的页码
                throw  new SellException(101,"太多人抢购了,请重试");
            }
            //查询库存若为0则,提示已抢购完
            Integer stockNum = productStock.get(productId);
            if(stockNum==0){
                throw new SellException(100,"已被抢购完了");
            }
            //下单
            ordered.put(KeyUtil.genUniqueKey(), productId);
            //减库存
            stockNum=stockNum-1;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //存入数据库
            productStock.put(productId,stockNum);
            //解锁
            redisLock.unlock(productId,time);
            //查询
            return query(productId);
        }
    setIfAbsent
  • 相关阅读:
    JDom写入XML例子
    hdu 2549
    hdu 1328
    hdu 1334
    hdu 2547
    hdu 2374
    hdu 2550
    hdu 1335
    hdu 2548
    hdu 1722
  • 原文地址:https://www.cnblogs.com/shouyaya/p/13258414.html
Copyright © 2011-2022 走看看