springboot之redis的分佈式鎖

一、 測試

    @Autowired
    private RedisLockHelper redisLockHelper;

    private static final String LOCK ="lock:equipment";
   
    // 14: 48執行
    //@Scheduled(cron = "0 48 14 ? * *")
    public void orderSync()  {
        long time = System.currentTimeMillis() + (10*1000);
        //進行加鎖操作
        if (redisLockHelper.lock(LOCK, time)) {
            System.out.println("加鎖");
        }else {
            System.out.println("解鎖");
            redisLockHelper.unlock(LOCK,time);
        }
    }

 

二、操作redis的工具類

package com.kmnfsw.util;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 *
 * @author wyg
 */
@Component
@Slf4j
public class RedisLockHelper {
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 加鎖
     * @param target   唯一標誌
     * @param timeStamp  當前時間+超時時間 也就是時間戳
     * @return
     */
    public boolean lock(String target, long timeStamp){
        // 如果鍵不存在則新增,存在則不改變已經有的值。
        if(redisTemplate.opsForValue().setIfAbsent(target,timeStamp)){
            return true;
        }

        // 判斷鎖超時 - 防止原來的操作異常,沒有運行解鎖操作  防止死鎖
        long currentLock = (long) redisTemplate.opsForValue().get(target);
        // 如果鎖過期 currentLock不爲空且小於當前時間
        if(currentLock < System.currentTimeMillis()){
            // 獲取上一個鎖的時間value 對應getset,如果lock存在 設置給過來的值,並返回舊的值
            long preLock = (long) redisTemplate.opsForValue().getAndSet(target,timeStamp);

            // 假設兩個線程同時進來這裏,因爲key被佔用了,而且鎖過期了。獲取的值currentLock=A(get取的舊的值肯定是一樣的),兩個線程的timeStamp都是B,key都是K.鎖時間已經過期了。
            // 而這裏面的getAndSet一次只會一個執行,也就是一個執行之後,上一個的timeStamp已經變成了B。只有一個線程獲取的上一個值會是A,另一個線程拿到的值是B。
            if(preLock==currentLock){
                // preLock不爲空且preLock等於currentLock,也就是校驗是不是上個對應的商品時間戳,也是防止併發
                return true;

            }
        }
        return false;
    }


    /**
     * 解鎖
     * @param target
     * @param timeStamp
     */
    public void unlock(String target,long timeStamp){
        try {
            long currentValue = (long) redisTemplate.opsForValue().get(target);
            if( currentValue<=timeStamp){
                // 刪除鎖狀態
                redisTemplate.opsForValue().getOperations().delete(target);
            }
        } catch (Exception e) {
            log.error("警報!警報!警報!解鎖異常{}",e);
        }
    }
}

 

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