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圣经