如何使用Redis实现分布式锁

dj699 / 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分布式锁,从而确保分布式系统中的线程安全。