一:业务锁
在代码业务逻辑加锁,防止不同业务操作相同业务表导致数据错乱,设置锁进行等待。这里锁使用的是ReentrantLock。详细的介绍可以参考:
https://blog.csdn.net/jerry11112/article/details/112375167
@Slf4j
public class MyLock {
private static ConcurrentHashMap<Long, ReentrantLock> reenTranLock = new ConcurrentHashMap<>();
/**
* 业务加锁
* @param businessId 业务id
* @param lockCode 需要加锁的代码,执行完后自动解锁
* @param timeOutSeconds 锁超时时间
* @return
**/
public static <T> T lockAndUnLock(Long businessId, Supplier<T> lockCode, long timeOutSeconds) {
try {
//可重入公平锁:true-公平锁,false-非公平锁
ReentrantLock lock = reenTranLock.putIfAbsent(businessId, new ReentrantLock(true));
lock = lock != null ? lock : reenTranLock.get(businessId);
//超时加锁,单位秒
boolean lockSuccess = lock.tryLock(timeOutSeconds, TimeUnit.SECONDS);
if (lockSuccess) {
try {
return lockCode.get();
} catch (Exception ex) {
throw ex;
} finally {
//解锁
lock.unlock();
}
} else {
throw new Exception("操作失败");
}
} catch (Exception ex) {
if (ex instanceof IllegalStateException) {
throw new IllegalStateException(ex.getMessage());
}
throw new RuntimeException(ex);
}
}
/**
* 加锁和解锁默认60S超时
* @param businessId 业务id
* @param lockCode 需要加锁的代码,执行完后自动解锁
* @return
**/
public static <T> T lockAndUnLock(Long businessId, Supplier<T> lockCode) {
return lockAndUnLock(businessId, lockCode, 60);
}
public static void main(String[] args) {
Boolean a = lockAndUnLock(1L, () -> {
String aaa = "111111";
return true;
});
System.out.println(a);
}
}
二:定时任务锁
当多个负载服务同时启用相同程序定时任务,需加上分布式锁,这里使用的是redis加锁。
@Slf4j
public class TaskTest {
@Autowired
private RedisTemplate redisTemplate;
@Scheduled(cron = "0 0/10 * * * ?")
public void task() {
//redis key名称
String redisKey = "test".concat(":").concat(this.getClass().getSimpleName()).concat("task");
//加上redis锁,适应分布式场景
boolean setOk = redisTemplate.opsForValue().setIfAbsent(redisKey, redisKey, 10, TimeUnit.SECONDS); //单位秒:根据不同的业务处理,自行设置大小时间
if (!setOk) {
log.info(redisKey + "任务已执行");
return;
}
try {
//业务逻辑处理.....
} catch (Exception ex) {
log.error("定时任务异常", ex.getMessage());
} finally {
//手动解锁
redisTemplate.delete(redisKey);
}
}
}