分布式锁是用来在分布式系统下控制对资源的独占访问,确保多个进程或线程不会同时操作同一资源。Redis 是实现分布式锁的常用工具之一。下面是详细的实现步骤和代码示例:
1. Redis 分布式锁的基本实现
通过设置一个唯一的键来实现锁,当操作完成后删除该键即可释放锁。
1.1 获取锁
使用 SET 命令并设置过期时间。NX 参数表示只有在键不存在时才能设置成功,EX 参数用于设置键的过期时间。
bash
SET lock_key unique_value NX EX 10
1.2 释放锁
只有持有锁的客户端才能删除锁。为了确保这一点,需要在释放锁时进行唯一值验证。
bash
# Lua脚本原子性地检查唯一值并删除锁
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
2. Java 实现 Redis 分布式锁
2.1 引入依赖
在 Maven 项目中引入 Jedis 依赖:
xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
2.2 获取锁的方法
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class RedisDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
private int expireTime;
public RedisDistributedLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockValue = lockValue;
this.expireTime = expireTime;
}
public boolean acquireLock() {
SetParams setParams = new SetParams();
setParams.nx().ex(expireTime);
// 尝试获取锁
String result = jedis.set(lockKey, lockValue, setParams);
return "OK".equals(result);
}
public boolean releaseLock() {
// 释放锁的 Lua 脚本
String luaScript =
"if redis.call('GET', KEYS[1]) == ARGV[1] then " +
"return redis.call('DEL', KEYS[1]) " +
"else " +
"return 0 " +
"end";
Object result = jedis.eval(luaScript, 1, lockKey, lockValue);
return "1".equals(result.toString());
}
public static void main(String[] args) {
// 连接到本地 Redis 服务
Jedis jedis = new Jedis("localhost");
String lockKey = "distributed_lock";
String lockValue = "unique_value";
int expireTime = 10; // 锁的过期时间,单位为秒
RedisDistributedLock lock = new RedisDistributedLock(jedis, lockKey, lockValue, expireTime);
// 获取锁
if (lock.acquireLock()) {
try {
// 执行你的逻辑
System.out.println("Lock acquired!");
// 模拟业务处理时间
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁
if (lock.releaseLock()) {
System.out.println("Lock released!");
} else {
System.out.println("Failed to release lock!");
}
}
} else {
System.out.println("Failed to acquire lock!");
}
jedis.close();
}
}
3. Redisson 提供的分布式锁
Redisson 是一个开源的 Redis 客户端,提供了更高级的分布式锁实现,与 Java 的java.util.concurrent.locks.Lock接口兼容。
3.1 引入依赖
在 Maven 项目中引入 Redisson 依赖:
xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.5</version>
</dependency>
3.2 使用 Redisson 实现分布式锁
java
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import java.util.concurrent.TimeUnit;
public class RedissonDistributedLock {
public static void main(String[] args) {
// 创建 Redisson 配置
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 创建 Redisson 客户端
RedissonClient redissonClient = Redisson.create(config);
// 获取锁对象
RLock lock = redissonClient.getLock("distributed_lock");
try {
// 尝试获取锁,等待时间10秒,持有锁30秒
if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
try {
// 执行你的逻辑
System.out.println("Lock acquired!");
// 模拟业务处理时间
Thread.sleep(5000);
} finally {
// 释放锁
lock.unlock();
System.out.println("Lock released!");
}
} else {
System.out.println("Failed to acquire lock!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
redissonClient.shutdown();
}
}
}
总结
通过配置 Redis 和编写合适的代码,可以实现可靠的分布式锁。上述示例展示了如何使用 Jedis 和 Redisson 来实现分布式锁。使用 Jedis 提供了更灵活的低级实现,而 Redisson 提供了更高级别的 API,使得分布式锁的使用更加简单和直观。选择合适的工具和方法取决于具体的应用场景和需求。