Redis分佈式鎖實現以及避免死鎖

分佈式鎖:當多個進程不在同一個系統中,用分佈式鎖控制多個進程對資源的訪問 

 

分佈式鎖應該具備哪些條件

  • 在分佈式系統環境下,一個方法在同一時間只能被一個機器的一個線程執行
  • 高可用的獲取鎖與釋放鎖
  • 高性能的獲取鎖與釋放鎖
  • 具備可重入特性(可理解爲重新進入,由多於一個任務併發使用,而不必擔心數據錯誤)
  • 具備鎖失效機制,防止死鎖
  • 具備非阻塞鎖特性,即沒有獲取到鎖將直接返回獲取鎖失敗


import com.demo.common.RedissonManager;

import org.redisson.api.RLock;

@Component
@Slf4j
public class CloseOrderTask {

    @Autowired
    private IOrderService iOrderService;

    @Autowired
    private RedissonManager redissonManager;

    @PreDestroy
    public void delLock(){
        RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);

    }

//    @Scheduled(cron="0 */1 * * * ?")//每1分鐘(每個1分鐘的整數倍)
    public void closeOrderTaskV1(){
        log.info("關閉訂單定時任務啓動");
        int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
//        iOrderService.closeOrder(hour);
        log.info("關閉訂單定時任務結束");
    }

//    @Scheduled(cron="0 */1 * * * ?")
    public void closeOrderTaskV2(){
        log.info("關閉訂單定時任務啓動");
        long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));

        Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
        if(setnxResult != null && setnxResult.intValue() == 1){
            //如果返回值是1,代表設置成功,獲取鎖
            closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        }else{
            log.info("沒有獲得分佈式鎖:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        }
        log.info("關閉訂單定時任務結束");
    }

    @Scheduled(cron="0 */1 * * * ?")
    public void closeOrderTaskV3(){
        log.info("關閉訂單定時任務啓動");
        long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
        Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
        if(setnxResult != null && setnxResult.intValue() == 1){
            closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        }else{
            //未獲取到鎖,繼續判斷,判斷時間戳,看是否可以重置並獲取到鎖。如果當前時間已經大於之前設置的時間則可以失效了
            String lockValueStr = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            if(lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)){
                String getSetResult = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
                //再次用當前時間戳getset。
                //返回給定的key的舊值,->舊值判斷,是否可以獲取鎖
                //當key沒有舊值時,即key不存在時,返回nil ->獲取鎖
                //這裏我們set了一個新的value值,獲取舊的值。
                if(getSetResult == null || (getSetResult != null && StringUtils.equals(lockValueStr,getSetResult))){
                    //真正獲取到鎖
                    closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }else{
                    log.info("沒有獲取到分佈式鎖:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }
            }else{
                log.info("沒有獲取到分佈式鎖:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            }
        }
        log.info("關閉訂單定時任務結束");
    }

//    @Scheduled(cron="0 */1 * * * ?")
    public void closeOrderTaskV4(){
        RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        boolean getLock = false;
        try {
                //注意這個0
            if(getLock = lock.tryLock(0,50, TimeUnit.SECONDS)){
                log.info("Redisson獲取到分佈式鎖:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
                int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
//                iOrderService.closeOrder(hour);
            }else{
                log.info("Redisson沒有獲取到分佈式鎖:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            log.error("Redisson分佈式鎖獲取異常",e);
        } finally {
            if(!getLock){
                return;
            }
            lock.unlock();
            log.info("Redisson分佈式鎖釋放鎖");
        }
    }




    private void closeOrder(String lockName){
        RedisShardedPoolUtil.expire(lockName,5);//有效期50秒,防止死鎖
        log.info("獲取{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
        int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
        iOrderService.closeOrder(hour);
        RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        log.info("釋放{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
        log.info("===============================");
    }




}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章