分布式鎖Redis實(shí)現(xiàn)

?????上篇講了分布式鎖的數(shù)據(jù)庫實(shí)現(xiàn),這篇我們繼續(xù)來講分布式鎖的redis實(shí)現(xiàn)。
那么如何通過redis來實(shí)現(xiàn)一個(gè)分布式鎖呢? 一般最容易想到的命令,就是setNx
那在使用redis setNx命令時(shí),還需要關(guān)注哪些點(diǎn)呢?

  1. redis分布式鎖常用命令,SETNX(key, val)
    當(dāng)且僅當(dāng)key不存在時(shí),設(shè)置成功,返回“1”,否者什么都不做,返回“0”
    我們可以利用該命令的特性進(jìn)行加鎖操作。
    假如同時(shí)有兩個(gè)線程要競(jìng)爭資源,其中一個(gè)線程先獲取到資源,調(diào)用setnx命令,將設(shè)置成功,返回“1”,表示加鎖成功。另一個(gè)線程也調(diào)用setnx命令,返回“0”,表示該key已經(jīng)設(shè)置過了,加鎖失敗,需要重新等待。

  2. expire key timeout
    為了防止,加鎖過程中出現(xiàn)異常,鎖一直不釋放,需要給加鎖的key,設(shè)置一個(gè)超時(shí)時(shí)間,超時(shí)時(shí)間的設(shè)置,是所有的分布式鎖實(shí)現(xiàn)都需要考慮的。

  3. delete key
    刪除某個(gè)key,釋放對(duì)應(yīng)的鎖。

下面是簡單的源碼實(shí)現(xiàn):

/**
 * 分布式鎖的簡單實(shí)現(xiàn)代碼
 */
public class DistributedLock {

    private final JedisPool jedisPool;

    public DistributedLock(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }

    /**
     * 加鎖
     * @param lockName       鎖的key
     * @param acquireTimeout 獲取超時(shí)時(shí)間
     * @param timeout        鎖的超時(shí)時(shí)間
     * @return 鎖標(biāo)識(shí)
     */
    public String lockWithTimeout(String lockName, long acquireTimeout, long timeout) {
        Jedis conn = null;
        String retIdentifier = null;
        try {
            // 獲取連接
            conn = jedisPool.getResource();
            // 隨機(jī)生成一個(gè)value
            String identifier = UUID.randomUUID().toString();
            // 鎖名,即key值
            String lockKey = "lock:" + lockName;
            // 超時(shí)時(shí)間,上鎖后超過此時(shí)間則自動(dòng)釋放鎖
            int lockExpire = (int) (timeout / 1000);

            // 獲取鎖的超時(shí)時(shí)間,超過這個(gè)時(shí)間則放棄獲取鎖
            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < end) {
                if (conn.setnx(lockKey, identifier) == 1) {
                    conn.expire(lockKey, lockExpire);
                    // 返回value值,用于釋放鎖時(shí)間確認(rèn)
                    retIdentifier = identifier;
                    return retIdentifier;
                }
                // 返回-1代表key沒有設(shè)置超時(shí)時(shí)間,為key設(shè)置一個(gè)超時(shí)時(shí)間
                if (conn.ttl(lockKey) == -1) {
                    conn.expire(lockKey, lockExpire);
                }

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        } catch (JedisException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
        return retIdentifier;
    }

    /**
     * 釋放鎖
     * @param lockName   鎖的key
     * @param identifier 釋放鎖的標(biāo)識(shí)
     * @return
     */
    public boolean releaseLock(String lockName, String identifier) {
        Jedis conn = null;
        String lockKey = "lock:" + lockName;
        boolean retFlag = false;
        try {
            conn = jedisPool.getResource();
            while (true) {
                // 監(jiān)視lock,準(zhǔn)備開始事務(wù)
                conn.watch(lockKey);
                // 通過前面返回的value值判斷是不是該鎖,若是該鎖,則刪除,釋放鎖
                if (identifier.equals(conn.get(lockKey))) {
                    Transaction transaction = conn.multi();
                    transaction.del(lockKey);
                    List<Object> results = transaction.exec();
                    if (results == null) {
                        continue;
                    }
                    retFlag = true;
                }
                conn.unwatch();
                break;
            }
        } catch (JedisException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
        return retFlag;
    }
}


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容