Java-很深我只知其一数据锁
·
代码锁工具类,重点是key生成策略
package com.lk.node.common.aspect;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 幂等性存储组件
* 使用内存存储幂等性状态,支持分布式环境
*
* @author CHENYB
* @since 2025-09-22
*/
@Slf4j
@Component
public class IdempotentStorage {
/**
* 存储幂等性锁的Map
* Key: 幂等性键
* Value: 锁对象和过期时间
*/
private final ConcurrentHashMap<String, LockInfo> lockMap = new ConcurrentHashMap<>();
/**
* 清理过期锁的定时任务间隔(毫秒)
*/
@Value("${idempotent.storage.cleanup-interval:3600000}")
private long cleanupInterval;
/**
* 锁过期时间(毫秒)
*/
@Value("${idempotent.storage.lock-expire-time:600000}")
private long lockExpireTime;
/**
* 上次清理时间
*/
private volatile long lastCleanupTime = System.currentTimeMillis();
/**
* 尝试获取锁
*
* @param key 幂等性键
* @param expireTime 过期时间
* @param timeUnit 时间单位
* @return true-获取成功,false-已存在
*/
public boolean tryLock(String key, long expireTime, TimeUnit timeUnit) {
long expireTimeMillis = System.currentTimeMillis() + timeUnit.toMillis(expireTime);
// 尝试创建新的锁信息
LockInfo newLockInfo = new LockInfo(expireTimeMillis);
LockInfo existingLockInfo = lockMap.putIfAbsent(key, newLockInfo);
if (existingLockInfo == null) {
// 成功创建新锁
log.debug("成功获取幂等性锁 - 键: {}, 过期时间: {}", key, expireTimeMillis);
return true;
} else {
// 锁已存在,检查是否过期
if (System.currentTimeMillis() > existingLockInfo.getExpireTime()) {
// 锁已过期,尝试替换
if (lockMap.replace(key, existingLockInfo, newLockInfo)) {
log.debug("替换过期锁成功 - 键: {}, 过期时间: {}", key, expireTimeMillis);
return true;
} else {
// 替换失败,说明有其他线程已经更新了锁
return false;
}
} else {
// 锁未过期,获取失败
log.debug("获取幂等性锁失败 - 键: {}, 剩余时间: {}ms",
key, existingLockInfo.getExpireTime() - System.currentTimeMillis());
return false;
}
}
}
/**
* 释放锁
*
* @param key 幂等性键
*/
public void releaseLock(String key) {
LockInfo removed = lockMap.remove(key);
if (removed != null) {
log.debug("释放幂等性锁 - 键: {}", key);
}
}
/**
* 检查锁是否存在且未过期
*
* @param key 幂等性键
* @return true-存在且未过期,false-不存在或已过期
*/
public boolean isLocked(String key) {
LockInfo lockInfo = lockMap.get(key);
if (lockInfo == null) {
return false;
}
if (System.currentTimeMillis() > lockInfo.getExpireTime()) {
// 锁已过期,移除
lockMap.remove(key, lockInfo);
return false;
}
return true;
}
/**
* 清理过期的锁
*/
private void cleanupExpiredLocks() {
long currentTime = System.currentTimeMillis();
// 避免频繁清理,设置最小间隔
if (currentTime - lastCleanupTime < cleanupInterval) {
return;
}
lastCleanupTime = currentTime;
int cleanedCount = 0;
for (String key : lockMap.keySet()) {
LockInfo lockInfo = lockMap.get(key);
if (lockInfo != null && currentTime > lockInfo.getExpireTime()) {
if (lockMap.remove(key, lockInfo)) {
cleanedCount++;
}
}
}
if (cleanedCount > 0) {
log.debug("清理过期锁完成 - 清理数量: {}, 当前锁数量: {}", cleanedCount, lockMap.size());
}
}
/**
* 获取当前锁的数量
*/
public int getLockCount() {
return lockMap.size();
}
/**
* 定时清理过期锁(使用配置的清理间隔)
*/
@Scheduled(fixedRateString = "${idempotent.storage.cleanup-interval:3600000}")
public void scheduledCleanup() {
try {
cleanupExpiredLocks();
log.info("定时清理幂等性锁完成 - 当前锁数量: {}, 清理间隔: {}ms", lockMap.size(), cleanupInterval);
} catch (Exception e) {
log.error("定时清理幂等性锁异常: {}", e.getMessage(), e);
}
}
/**
* 清空所有锁(用于测试)
*/
public void clearAll() {
lockMap.clear();
log.debug("清空所有幂等性锁");
}
/**
* 锁信息内部类
*/
private static class LockInfo {
private final long expireTime;
public LockInfo(long expireTime) {
this.expireTime = expireTime;
}
public long getExpireTime() {
return expireTime;
}
}
}
更多推荐
所有评论(0)