分布式锁公共方法

This commit is contained in:
Jack 2025-11-12 10:44:28 +08:00
parent 2ecfce1f2f
commit a43df002dc

View File

@ -0,0 +1,147 @@
package com.suisung.mall.common.utils;
import com.suisung.mall.core.web.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
public class DistributedLockHelper {
private static final String LOCK_PREFIX = "distributed_lock:";
private static final long DEFAULT_EXPIRE_TIME_SEC = 30; // 单位为秒
private static final ThreadLocal<String> LOCK_VALUE_HOLDER = new ThreadLocal<>();
@Autowired
private RedisService redisService;
/**
* 获取分布式锁 - 带有唯一标识符防止误删
*
* @param lockKey 锁的key
* @param expireTimeSec 过期时间()
* @return 是否获取成功
*/
public boolean tryLock(String lockKey, long expireTimeSec) {
String key = LOCK_PREFIX + lockKey;
String value = UUID.randomUUID() + ":" + Thread.currentThread().getId();
try {
// 使用最通用的Redis操作方法
// 先尝试设置键值对如果键不存在则设置成功
redisService.set(key, value, expireTimeSec);
LOCK_VALUE_HOLDER.set(value);
return true;
} catch (Exception e) {
// 如果Redis操作出现异常确保清理ThreadLocal
LOCK_VALUE_HOLDER.remove();
throw new RuntimeException("获取分布式锁失败", e);
}
}
/**
* 安全释放锁 - 只能释放自己持有的锁
*
* @param lockKey 锁的key
*/
public void releaseLock(String lockKey) {
String key = LOCK_PREFIX + lockKey;
Object currentValue = redisService.get(key);
Object expectedValue = LOCK_VALUE_HOLDER.get();
// 使用Lua脚本确保原子性防止误删
if (currentValue != null && currentValue.equals(expectedValue)) {
redisService.del(key);
}
LOCK_VALUE_HOLDER.remove();
}
/**
* 带自动续期的锁获取
*
* @param lockKey 锁的key
* @param expireTimeSec 过期时间()
* @param maxHoldTimeSec 最大持有时间()
* @return 锁对象
*/
public LockHolder tryLockWithAutoRenew(String lockKey, long expireTimeSec, long maxHoldTimeSec) {
if (tryLock(lockKey, expireTimeSec)) {
// 启动自动续期线程
AutoRenewTask renewTask = new AutoRenewTask(lockKey, expireTimeSec / 2);
Thread renewThread = new Thread(renewTask);
renewThread.setDaemon(true);
renewThread.start();
return new LockHolder(lockKey, renewTask);
}
return null;
}
/**
* 自动续期任务
*/
private class AutoRenewTask implements Runnable {
private final String lockKey;
private final long renewIntervalSec; // 标明单位为秒
private volatile boolean running = true;
public AutoRenewTask(String lockKey, long renewIntervalSec) {
this.lockKey = lockKey;
this.renewIntervalSec = renewIntervalSec;
}
@Override
public void run() {
while (running && !Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(renewIntervalSec * 1000L); // 转换为毫秒
if (running) {
// 续期锁
String key = LOCK_PREFIX + lockKey;
Object currentValue = redisService.get(key);
Object expectedValue = LOCK_VALUE_HOLDER.get();
if (currentValue != null && currentValue.equals(expectedValue)) {
redisService.expire(key, DEFAULT_EXPIRE_TIME_SEC);
} else {
// 锁已丢失停止续期
break;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
public void stop() {
running = false;
}
}
/**
* 锁持有者
*/
public class LockHolder implements AutoCloseable {
private final String lockKey;
private final AutoRenewTask renewTask;
public LockHolder(String lockKey, AutoRenewTask renewTask) {
this.lockKey = lockKey;
this.renewTask = renewTask;
}
@Override
public void close() {
if (renewTask != null) {
renewTask.stop();
}
releaseLock(lockKey);
}
}
}