Redis分布式锁在很多需要协调多个分布式系统或组件的场景中都能发挥重要作用。以下是一些常见的使用场景以及相应的代码示例:
常见使用场景
-
防止资源竞争:
- 多个进程或线程需要访问同一共享资源时,使用分布式锁可以防止资源竞争,确保同一时间只有一个进程或线程在操作该资源。
-
定时任务调度:
- 在分布式系统中,确保某个定时任务在同一时刻只被一个调度器执行,避免重复执行任务。
-
库存扣减:
- 电商系统中,多个用户同时下单时,需要确保库存扣减操作的原子性和一致性。
-
分布式事务:
- 在跨多个服务的分布式事务中,使用分布式锁可以协调各服务的操作,确保事务的一致性。
-
ID生成器:
- 分布式系统中生成全局唯一ID时,使用分布式锁可以确保ID的唯一性和有序性。
场景示例和相应代码
1. 防止资源竞争
假设有多个进程同时写入一个文件,我们需要确保同一时间只有一个进程在写入。
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class FileWriteWithDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
private int expireTime;
public FileWriteWithDistributedLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.expireTime = expireTime;
this.lockValue = String.valueOf(Thread.currentThread().getId());
}
public boolean acquireLock() {
SetParams params = new SetParams().nx().px(expireTime);
String result = jedis.set(lockKey, lockValue, params);
return "OK".equals(result);
}
public boolean releaseLock() {
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 result.equals(1L);
}
public void writeToFile(String content) {
if (acquireLock()) {
try {
// 模拟文件写操作
System.out.println("Writing to file: " + content);
} finally {
boolean released = releaseLock();
if (released) {
System.out.println("Lock released after writing.");
} else {
System.out.println("Failed to release lock.");
}
}
} else {
System.out.println("Failed to acquire lock, try again later.");
}
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
FileWriteWithDistributedLock fileLock = new FileWriteWithDistributedLock(jedis, "file_write_lock", 10000);
fileLock.writeToFile("Hello, World!");
jedis.close();
}
}
2. 定时任务调度
确保定时任务在分布式系统中同一时刻只被一个节点执行。
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class ScheduledTaskWithDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
private int expireTime;
public ScheduledTaskWithDistributedLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.expireTime = expireTime;
this.lockValue = String.valueOf(Thread.currentThread().getId());
}
public boolean acquireLock() {
SetParams params = new SetParams().nx().px(expireTime);
String result = jedis.set(lockKey, lockValue, params);
return "OK".equals(result);
}
public boolean releaseLock() {
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 result.equals(1L);
}
public void executeScheduledTask() {
if (acquireLock()) {
try {
// 执行定时任务
System.out.println("Executing scheduled task.");
} finally {
boolean released = releaseLock();
if (released) {
System.out.println("Lock released after executing task.");
} else {
System.out.println("Failed to release lock.");
}
}
} else {
System.out.println("Failed to acquire lock, another instance might be executing the task.");
}
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
ScheduledTaskWithDistributedLock taskLock = new ScheduledTaskWithDistributedLock(jedis, "scheduled_task_lock", 10000);
taskLock.executeScheduledTask();
jedis.close();
}
}
3. 库存扣减
在电商系统中,同时对同一个商品下单时需要确保库存扣减操作的原子性。
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class InventoryReductionWithDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
private int expireTime;
public InventoryReductionWithDistributedLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.expireTime = expireTime;
this.lockValue = String.valueOf(Thread.currentThread().getId());
}
public boolean acquireLock() {
SetParams params = new SetParams().nx().px(expireTime);
String result = jedis.set(lockKey, lockValue, params);
return "OK".equals(result);
}
public boolean releaseLock() {
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 result.equals(1L);
}
public void reduceInventory(String itemId, int quantity) {
if (acquireLock()) {
try {
// 模拟库存扣减操作
System.out.println("Reducing inventory for item: " + itemId + " by " + quantity);
} finally {
boolean released = releaseLock();
if (released) {
System.out.println("Lock released after reducing inventory.");
} else {
System.out.println("Failed to release lock.");
}
}
} else {
System.out.println("Failed to acquire lock, try again later.");
}
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
InventoryReductionWithDistributedLock inventoryLock = new InventoryReductionWithDistributedLock(jedis, "inventory_lock", 10000);
inventoryLock.reduceInventory("item123", 1);
jedis.close();
}
}
4. 分布式事务
在跨多个服务的分布式事务中,通过分布式锁来协调操作,确保事务的一致性。
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class DistributedTransactionWithLock {
private Jedis jedis;
private String lockKey;
private String lockValue;
private int expireTime;
public DistributedTransactionWithLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.expireTime = expireTime;
this.lockValue = String.valueOf(Thread.currentThread().getId());
}
public boolean acquireLock() {
SetParams params = new SetParams().nx().px(expireTime);
String result = jedis.set(lockKey, lockValue, params);
return "OK".equals(result);
}
public boolean releaseLock() {
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 result.equals(1L);
}
public void executeDistributedTransaction() {
if (acquireLock()) {
try {
// 执行分布式事务的协调操作
System.out.println("Executing distributed transaction.");
} finally {
boolean released = releaseLock();
if (released) {
System.out.println("Lock released after executing transaction.");
} else {
System.out.println("Failed to release lock.");
}
}
} else {
System.out.println("Failed to acquire lock, try again later.");
}
}