18.7.5 Redis分布式锁实现与优化
1. Redis分布式锁基础实现
1.1 基础分布式锁
public class RedisDistributedLock {
/*
* Redis分布式锁基础实现:
*
* 1. 核心命令
* - SET key value NX PX milliseconds
* - NX: 只在键不存在时设置
* - PX: 设置过期时间(毫秒)
*
* 2. 基本流程
* - 获取锁:SET操作成功
* - 释放锁:DEL操作删除
* - 超时释放:自动过期
*
* 3. 问题与改进
* - 锁误删问题
* - 锁续期问题
* - 可重入问题
*/
public void demonstrateBasicLock() {
System.out.println("=== Redis分布式锁基础实现演示 ===");
MockRedisClient redis = new MockRedisClient();
BasicDistributedLock lock = new BasicDistributedLock(redis);
// 演示基础锁操作
demonstrateLockOperations(lock);
// 演示并发场景
demonstrateConcurrentLock(lock);
}
private void demonstrateLockOperations(BasicDistributedLock lock) {
System.out.println("--- 基础锁操作 ---");
String lockKey = "order:lock:1001";
String requestId = "req-" + System.currentTimeMillis();
System.out.println("1. 尝试获取锁:");
boolean acquired = lock.tryLock(lockKey, requestId, 30000);
System.out.println("获取锁结果: " + acquired);
if (acquired) {
System.out.println("\n2. 执行业务逻辑:");
System.out.println("处理订单业务...");
try {
Thread.sleep(1000); // 模拟业务处理时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("\n3. 释放锁:");
boolean released = lock.unlock(lockKey, requestId);
System.out.println("释放锁结果: " + released);
}
}
private void demonstrateConcurrentLock(BasicDistributedLock lock) {
System.out.println("\n--- 并发锁测试 ---");
String lockKey = "concurrent:lock:test";
// 启动多个线程竞争锁
for (int i = 1; i <= 5; i++) {
final int threadId = i;
new Thread(() -> {
String requestId = "thread-" + threadId;
boolean acquired = lock.tryLock(lockKey, requestId, 10000);
if (acquired) {
System.out.println("线程" + threadId + " 获取锁成功");
try {
Thread.sleep(2000); // 模拟业务处理
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
lock.unlock(lockKey, requestId);
System.out.println("线程" + threadId + " 释放锁");
} else {
System.out.println("线程" + threadId + " 获取锁失败");
}
}).start();
}
}
}
// 模拟Redis客户端
class MockRedisClient {
private java.util.Map<String, String> data = new java.util.concurrent.ConcurrentHashMap<>();
private java.util.Map<String, Long> expireTime = new java.util.concurrent.ConcurrentHashMap<>();
public boolean setNX(String key, String value, long expireMs) {
// 检查过期
if (expireTime.containsKey(key) && System.currentTimeMillis() > expireTime.get(key)) {
data.remove(key);
expireTime.remove(key);
}
// 尝试设置
if (!data.containsKey(key)) {
data.put(key, value);
expireTime.put(key, System.currentTimeMillis() + expireMs);
System.out.println(" Redis SET " + key + " " + value + " NX PX " + expireMs + " -> OK");
return true;
} else {
System.out.println(" Redis SET " + key + " " + value + " NX PX " + expireMs + " -> NIL");
return false;
}
}
public String get(String key) {
// 检查过期
if (expireTime.containsKey(key) && System.currentTimeMillis() > expireTime.get(key)) {
data.remove(key);
expireTime.remove(key);
return null;
}
return data.get(key);
}
public boolean delete(String key, String expectedValue) {
String currentValue = get(key);
if (expectedValue.equals(currentValue)) {
data.remove(key);
expireTime.remove(key);
System.out.println(" Redis DEL " + key + " -> 1");
return true;
} else {
System.out.println(" Redis DEL " + key + " -> 0 (value mismatch)");
return false;
}
}
public Object eval(String script, java.util.List<String> keys, java.util.List<String> args) {
System.out.println(" Redis EVAL script with keys: " + keys + ", args: " + args);
// 模拟Lua脚本执行
if (script.contains("redis.call('get', KEYS[1])")) {
String key = keys.get(0);
String expectedValue = args.get(0);
String currentValue = get(key);
if (expectedValue.equals(currentValue)) {
data.remove(key);
expireTime.remove(key);
return 1L;
} else {
return 0L;
}
}
return 0L;
}
}
// 基础分布式锁实现
class BasicDistributedLock {
private MockRedisClient redis;
public BasicDistributedLock(MockRedisClient redis) {
this.redis = redis;
}
public boolean tryLock(String lockKey, String requestId, long expireMs) {
return redis.setNX(lockKey, requestId, expireMs);
}
public boolean unlock(String lockKey, String requestId) {
// 使用Lua脚本保证原子性
String script =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
Object result = redis.eval(script,
java.util.Arrays.asList(lockKey),
java.util.Arrays.asList(requestId));
return Long.valueOf(1).equals(result);
}
}
2. 高级分布式锁实现
2.1 可重入分布式锁
public class ReentrantDistributedLock {
/*
* 可重入分布式锁:
*
* 1. 可重入特性
* - 同一线程可多次获取锁
* - 记录重入次数
* - 释放时递减计数
*
* 2. 实现方案
* - 使用Hash结构存储
* - field: 线程标识
* - value: 重入次数
*
* 3. 锁续期机制
* - 看门狗自动续期
* - 避免业务执行时间过长导致锁过期
*/
public void demonstrateReentrantLock() {
System.out.println("=== 可重入分布式锁演示 ===");
MockRedisClient redis = new MockRedisClient();
AdvancedDistributedLock lock = new AdvancedDistributedLock(redis);
demonstrateReentrantFeature(lock);
demonstrateWatchdog(lock);
}
private void demonstrateReentrantFeature(AdvancedDistributedLock lock) {
System.out.println("--- 可重入特性演示 ---");
String lockKey = "reentrant:lock:test";
String threadId = Thread.currentThread().getName();
System.out.println("1. 第一次获取锁:");
boolean acquired1 = lock.lock(lockKey, threadId, 30000);
System.out.println("获取结果: " + acquired1);
System.out.println("\n2. 第二次获取锁 (重入):");
boolean acquired2 = lock.lock(lockKey, threadId, 30000);
System.out.println("获取结果: " + acquired2);
System.out.println("\n3. 第三次获取锁 (重入):");
boolean acquired3 = lock.lock(lockKey, threadId, 30000);
System.out.println("获取结果: " + acquired3);
System.out.println("\n4. 释放锁:");
lock.unlock(lockKey, threadId);
System.out.println("5. 再次释放锁:");
lock.unlock(lockKey, threadId);
System.out.println("6. 最后释放锁:");
lock.unlock(lockKey, threadId);
}
private void demonstrateWatchdog(AdvancedDistributedLock lock) {
System.out.println("\n--- 看门狗续期演示 ---");
String lockKey = "watchdog:lock:test
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经
