基於redis集群實現的分布式鎖,可用於秒殺,定時器。


在分布式系統中,經常會出現需要競爭同一資源的情況,使用redis可以實現分布式鎖。

前提:redis集群已經整合項目,並且可以直接注入JedisCluster使用:

    @Autowired
    private JedisCluster jedisCluster;

 

1. 新建RedisLockManger分布式鎖管理器,並且如上注入 JedisCluster :

package com.jarfk.util.redis;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis集群分布式鎖管理器,支持對單個資源加鎖解鎖,或給一批資源的批量加鎖及解鎖
 * Created by Administrator on 2017/10/12 0012.
 */
@Component
public class RedisLockManger {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockManger.class);

    //設置3秒過期
    private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3;

    //    private static final int DEFAULT_BATCH_EXPIRE_TIME = 6;

    //static的變量無法注解
    @Autowired
    private JedisCluster jc;

    private static RedisLockManger lockManger;

    public RedisLockManger() {
    }

    @PostConstruct
    private void init() {
        lockManger = this;
        lockManger.jc = this.jc;
    }
    /**
     * 獲取鎖 如果鎖可用   立即返回true,  否則立即返回false,作為非阻塞式鎖使用
     * @param key
     * @return
     */
    public boolean tryLock(String key/* , String value*/) {
        try {
            return tryLock(key, key, 0L, null);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 鎖在給定的等待時間內空閑,則獲取鎖成功 返回true, 否則返回false,作為阻塞式鎖使用
     * @param key 鎖鍵
     * @param value 被誰鎖定
     * @param timeout 嘗試獲取鎖時長,建議傳遞500,結合實踐單位,則可表示500毫秒
     * @param unit,建議傳遞TimeUnit.MILLISECONDS
     * @return
     * @throws InterruptedException
     */
    public boolean tryLock(String key , String value , long timeout , TimeUnit unit) throws InterruptedException {
        //納秒
        long begin = System.nanoTime();
        do {
            //LOGGER.debug("{}嘗試獲得{}的鎖.", value, key);
            Long i = lockManger.jc.setnx(key, value);
            if (i == 1) {
                lockManger.jc.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
                LOGGER.debug(value + "-成功獲取{}的鎖,設置鎖過期時間為{}秒 ", key, DEFAULT_SINGLE_EXPIRE_TIME);
                return true;
            } else {
                // 存在鎖 ,但可能獲取不到,原因是獲取的一剎那間
//                String desc = lockManger.jc.get(key);
//                LOGGER.error("{}正被{}鎖定.", key, desc);
            } if (timeout == 0) {
                break;
            }
            //在其睡眠的期間,鎖可能被解,也可能又被他人占用,但會嘗試繼續獲取鎖直到指定的時間
            Thread.sleep(100);
        } while ((System.nanoTime() - begin) < unit.toNanos(timeout));
        //因超時沒有獲得鎖
        return false;
    }

    /**
     * 釋放單個鎖
     * @param key 鎖鍵
     */
    public void unLock(String key/*, String value*/) {
        lockManger.jc.del(key);
        LOGGER.debug("{}鎖被{}釋放 .", key, key);
    }
}

 

2. 使用示例:

首先在需要加鎖的地方注入分布式鎖管理器:

    @Autowired
    private RedisLockManger redisLock;

然后調用即可,如:

        if (redisLock.tryLock("statusCheck")) { //此處代碼是鎖上的
            logger.debug("-----------------------:10秒執行一次!每次只有一個程序運行");
            //釋放鎖,正常情況下,此處代碼要注釋掉,以免鎖被釋放,需要釋放時可以根據自己邏輯的需要 
            //redisLock.unLock("statusCheck");
        }

 

 

首先注入需要的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM