1. 程式人生 > >定時器+redis分散式鎖、定時器+redisson框架分散式鎖

定時器+redis分散式鎖、定時器+redisson框架分散式鎖

定時器+redis分散式鎖

在xml中新增:

<task:annotation-driven/>

1. 不帶鎖的定時器:

2. 帶redis分散式鎖的定時器:

原理:設定鎖的lokkey,值為當前毫秒值+超時毫秒值,redis的setnx方法為,如果不存在lokkey,返回1並設定lokkey,返回0,代表已存在鎖

程式碼

3.上面的方法雖然好,但是如果在設定鎖的有效期之前,tomcat異常關閉,比如:殺死tomcat程序,在redis中已經存在鎖,這種情況會出現死鎖,所以需要進行改進

優化版:設定鎖的lokkey,值為當前毫秒值+超時毫秒值,redis的setnx方法為,如果不存在lokkey,返回1並設定lokkey,返回0,代表已存在鎖

返回0時,判斷當前時間是否為空&&是否 > redis的value值 lockvalueA

{

不為空且大於:使用getset方法,設定值為當前毫秒+超時毫秒,返回舊值 lockvalueB,判斷lockvalueB是否為空 || (lockvalueB不為空且lockvalueA==lockvalueB)

    {

         lockvalueB為空:代表走到這一步,別的tomcat已經執行了一遍程式碼並且釋放了鎖

         lockvalueB不為空且lockvalueA==lockvalueB:代表開啟定時後第一次執行此程式碼

         lockvalueA != lockvalueB:代表別的tomcat已經在執行此程式碼,並且鎖還未被釋放

    }

不為空且小於:結束

為空:結束

}

程式碼

@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("關閉訂單定時任務結束");
    }

定時器+redisson框架分散式鎖

使用這個方法程式碼會簡單很多

在pom.xml中新增:

<dependency>
      <groupId>org.redisson</groupId>
      <artifactId>redisson</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-avro</artifactId>
      <version>2.9.0</version>
    </dependency>

RedissonManager類

@Component
@Slf4j
public class RedissonManager {

    private Config config = new Config();

    private Redisson redisson = null;

    public Redisson getRedisson() {
        return redisson;
    }

    private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
    private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));
    private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
    private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));

    @PostConstruct
    private void init(){
        try {
            config.useSingleServer().setAddress(new StringBuilder().append(redis1Ip).append(":").append(redis1Port).toString());

            redisson = (Redisson) Redisson.create(config);

            log.info("初始化Redisson結束");
        } catch (Exception e) {
            log.error("redisson init error",e);
        }
    }



}