import cn.hutool.core.util.IdUtil;
import com.jovision.vse.console.core.constant.RedisConstant;
import com.jovision.vse.console.core.exception.BusinessErrorEnum;
import com.jovision.vse.console.core.exception.MixException;
import com.jovision.vse.console.core.model.LockContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.error.Mark;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Description 获取锁, 释放锁
* @Author FL
* @Date 11:29 2021/10/18
* @Param
**/
@Service
@Slf4j
public class DeviceLock {
@Autowired
StringRedisTemplate redisTemplate;
/**
* @Description 获取锁
* @Author FL
* @Date 11:35 2021/10/18
* @Param [tenantId]
**/
public LockContext getLock(String tenantId) {
return getLock(tenantId, null);
}
/**
* 获取锁
*
* @param tenantId 企业id
* @param type 锁的类型
* @return
*/
public LockContext getLock(String tenantId, String type) {
/**
* 一个租户一个锁,锁的自动释放时间为300ms
* 获取锁时正在被占用,120ms为间隔,最多重试三次,三次获取,均为被占用,提示当前系统繁忙,请稍后重试
**/
// 获取锁
String simpleUUID = IdUtil.simpleUUID();
String lockKey = RedisConstant.LOCK_KEY + "getRemainingChannelNumber:" + tenantId;
if (StringUtils.isNotBlank(type)) {
lockKey += ":" + type;
}
Boolean lockState = redisTemplate.opsForValue().setIfAbsent(lockKey
, simpleUUID, 300, TimeUnit.MILLISECONDS);
log.info("获取锁: 状态{} 值:{}", lockState, simpleUUID);
int maxRetryCount = 4;// 最大重试次数3次,一共4次
int index = 1;//抢占次数
while (!lockState) {
try {
Thread.sleep(120);
log.info("抢占失败线程: {} 租户:{}", Thread.currentThread().getId(), tenantId);
} catch (InterruptedException e) {
e.printStackTrace();
log.info(e.getMessage());
}
index++;
lockState = redisTemplate.opsForValue().setIfAbsent(lockKey
, simpleUUID, 300, TimeUnit.MILLISECONDS);
if (!lockState && index >= maxRetryCount) {
throw new MixException(BusinessErrorEnum.THE_SYSTEM_WAS_BUSY_EARLIER);
}
}
log.info("抢占成功线程: {} 租户:{}", Thread.currentThread().getId(), tenantId);
return LockContext.builder().key(lockKey).value(simpleUUID).build();
}
/**
* @Description 释放锁
* @Author FL
* @Date 11:35 2021/10/18
* @Param [key]
**/
public void releaseLock(LockContext lockContext) {
if(null != lockContext){
String value = lockContext.getValue();
String key = lockContext.getKey();
if (value.equals(redisTemplate.opsForValue().get(key))) {
log.info("释放锁: 值:{}", value);
redisTemplate.delete(key);
}
}
}
/**
* ===========废弃=========
* 获取锁
* 通道布控绑定,标记为该通道需要创建分组
* 任务执行加分布式锁,只创建一次分组
* 抢占成功,创建分组移除标记
* 抢占失败,重试是否获取到 创建分组 标记,重试三次;
* 标记获取成功且超过限制,默认任务失败; 标记获取失败且未超过限制,继续执行;
*/
public LockContext getFaceLock(String channelId) {
String lock_key_create = RedisConstant.LOCK_KEY + RedisConstant.FACE_CHANNEL + channelId;// 新增分组通道锁
String lock_key_mark = RedisConstant.LOCK_KEY + RedisConstant.FACE_GROUP + channelId;// 创建分组标记
String simpleUUID = IdUtil.simpleUUID();
// 获取锁
Boolean lockState = redisTemplate.opsForValue().setIfAbsent(lock_key_create,
simpleUUID, 500, TimeUnit.MILLISECONDS);
log.info("获取锁: 状态{} 值:{}", lockState, simpleUUID);
int maxRetryCount = 4;// 最大重试次数3次
int index = 0;//重试次数
while (!lockState) {
try {
Thread.sleep(220);
log.info("抢占失败线程: {} 通道:{}", Thread.currentThread().getId(), channelId);
} catch (InterruptedException e) {
e.printStackTrace();
log.info(e.getMessage());
}
index++;
Boolean markTry = redisTemplate.hasKey(lock_key_mark);
if (!markTry && index < maxRetryCount) {
return null;
}
if (markTry && index >= maxRetryCount) {
throw new MixException(BusinessErrorEnum.BASE_TOP_SERVER.getCode(), "任务执行失败");
}
}
log.info("抢占成功线程: {} 通道:{}", Thread.currentThread().getId(), channelId);
return LockContext.builder().key(lock_key_create).value(simpleUUID).build();
}
/**
* @Description 获取分布式锁
* @Author FL
* @Date 11:33 2022/1/12
* @Param [channelId] 锁的key重要组成
**/
public LockContext getDistributeLock(String channelId) {
String lock_key_create = RedisConstant.LOCK_KEY + RedisConstant.FACE_CHANNEL + channelId;// 新增分组通道锁
String simpleUUID = IdUtil.simpleUUID();
// 获取锁
Boolean lockState = redisTemplate.opsForValue().setIfAbsent(lock_key_create,
simpleUUID, 3000, TimeUnit.MILLISECONDS);
log.info("获取锁: 状态{} 值:{}", lockState, simpleUUID);
if (!lockState) {
log.info("抢占失败线程: {} 通道:{}", Thread.currentThread().getId(), channelId);
return null;
}
log.info("抢占成功线程: {} 通道:{}", Thread.currentThread().getId(), channelId);
return LockContext.builder().key(lock_key_create).value(simpleUUID).build();
}
/**
* @Description: 获取accesstokenLock
* @Param: [ak]
* @return: boolean
* @Author: zhaowenchao
* @Date: 2022/1/11
*/
public LockContext getAccessTokenLock(String ak){
// 获取锁
String simpleUUID = IdUtil.simpleUUID();
String lockKey = RedisConstant.LOCK_KEY + "getAccessToken:" + ak ;
Boolean lockState = redisTemplate.opsForValue().setIfAbsent(lockKey
, simpleUUID, 500, TimeUnit.MILLISECONDS);
log.info("getAccessTokenLock 获取锁: 状态{} 值:{}", lockState, simpleUUID);
if(lockState){
return LockContext.builder().key(lockKey).value(simpleUUID).build();
}else{
return null;
}
}
}
\