如何使用Redis實現分散式鎖

djπ發表於2024-07-17

在分散式系統中,保證多個程序或執行緒對共享資源的同步訪問是一個常見問題。鎖是一種常用的同步機制,但在單機環境中常用的鎖機制在分散式系統中往往不再適用。Redis,作為一種高效能的鍵值儲存系統,提供了實現分散式鎖的可能。本文將介紹如何使用Redis實現分散式鎖,並透過Java程式碼示例展示其實現過程。

分散式鎖的挑戰
在單機系統中,鎖的實現相對簡單,可以使用語言內建的同步機制。但在分散式系統中,不同的服務例項可能執行在不同的伺服器上,傳統的鎖機制無法跨服務例項同步。因此,需要一種跨服務例項的鎖機制,這就是分散式鎖。

Redis分散式鎖的優勢
高效能:Redis單執行緒的特性使其在處理鎖請求時具有高效能。
簡單易用:透過簡單的命令即可實現鎖的獲取和釋放。
可重入:支援同一執行緒多次獲取同一把鎖。
實現Redis分散式鎖
以下是一個使用Java和Spring框架實現Redis分散式鎖的示例:

  1. 引入依賴
    首先,確保你的專案中已經新增了Spring Data Redis和Apache Commons Lang的依賴。以下是Maven依賴配置示例:

xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>
  1. Redis分散式鎖工具類
    java
package com.csot.kms.common.util;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

public class RedisLockUtil {

    private static StringRedisTemplate redisTemplate = (StringRedisTemplate) SpringUtils.getBean("stringRedisTemplate");

    /**
     * 加鎖
     *
     * @param key   鎖的標識
     * @param value 當前時間+超時時間
     * @return      是否成功獲取鎖
     */
    public boolean lock(String key, String value) {
        if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
            return true;
        }
        String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
        // 如果鎖過期  解決死鎖
        if (StringUtils.isNotEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            String oldValue = String.valueOf(redisTemplate.opsForValue().getAndSet(key, value));
            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 解鎖
     *
     * @param key   鎖的標識
     * @param value 鎖的值
     */
    public void unlock(String key, String value) {
        try {
            String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 使用Redis分散式鎖
    在需要同步的程式碼塊中,使用 RedisLockUtil 類來獲取和釋放鎖:

java

public class SomeService {

    private RedisLockUtil redisLockUtil = new RedisLockUtil();

    public void someMethod() {
        String lockKey = "someLock";
        long expireTime = 30000; // 鎖的超時時間,30秒
        long currentTime = System.currentTimeMillis();
        String value = currentTime + "," + expireTime;

        boolean isLock = redisLockUtil.lock(lockKey, value);
        if (isLock) {
            try {
                // 執行業務邏輯
            } finally {
                redisLockUtil.unlock(lockKey, value);
            }
        } else {
            // 處理未能獲取鎖的情況
        }
    }
}

總結
Redis分散式鎖是一種簡單而有效的在分散式系統中同步訪問共享資源的方法。透過本文的示例程式碼,你可以在自己的專案中實現Redis分散式鎖,從而確保分散式系統中的執行緒安全。

相關文章