全局并发控制工具类

package com.iwhalecloud.iom.threadcontroller.utils;

import com.iwhalecloud.iom.base.utils.data.ZDateUtils;
import com.iwhalecloud.iom.base.utils.service.OssException;
import com.iwhalecloud.iom.common.cache.redis.RedisCacheInterface;
import com.iwhalecloud.iom.utils.helper.process.ProcessUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
* 全局并发控制工具类
*/
@Component
public class GlobalConcurrentUtils {
private static Logger logger = LoggerFactory.getLogger(GlobalConcurrentUtils.class);

@Autowired
RedisCacheInterface redisCacheInterface;

private static final String NX_LOCK_CACHE = "NX_GC_LOCK_CACHE";

private static int DEFAULT_LOCK_TIME = 30;


/**
* 清除掉所有value前缀为本进程UUID的key,释放掉锁
*
* @param globalLockCode 集群全局锁编码
* @param concurrentCount 并发数
* @return
*/
public long release(String globalLockCode, Integer concurrentCount) {
long result = 0;
String processUUID = ProcessUtils.getProcessInfo().getPid();

for (int i = 1; i <= concurrentCount; i++) {
String key = NX_LOCK_CACHE + "_" + globalLockCode + "-" + i;
String currentValueStr = (String) redisCacheInterface.get(key);
if (currentValueStr.indexOf(processUUID) >= 0) {
result += redisCacheInterface.del(key);
}
}
return result;
}


/**
* 全局并发控制操作,作用于应用集群范围内,保证任务只能在指定并发数内进行
*
* @param getLockTimeout 单位秒
* @param lockTime 单位秒
* @param globalLockCode 全局锁编码
* @param concurrentCount 全局并发数,大于1的暂时未详细完善。
* @param taskAction 任务操作
*/
public void process(String globalLockCode, Integer concurrentCount, TaskAction taskAction, Integer getLockTimeout, Integer lockTime, Integer tryGetlockInterval) {
boolean lockResult = false;
if (StringUtils.isEmpty(globalLockCode)) {
throw new OssException("传入的globalLockCode不能为空!!!");
}
if (lockTime == null) {
lockTime = DEFAULT_LOCK_TIME;
}
//获得进程UUID
String processUUID = ProcessUtils.getProcessInfo().getPid();
for (int i = 1; i <= concurrentCount; i++) {
long start = System.currentTimeMillis();

do {
String lockKey = NX_LOCK_CACHE + "_" + globalLockCode + "-" + i;

String lockValue = processUUID + "_" + (start + lockTime * 1000L);
//1.获取全局锁,并在指定时长后释放,保证进程宕机时,可以释放锁
lockResult = redisCacheInterface.setNX(lockKey, lockValue, lockTime);
if (!lockResult) {
logger.info("集群并发锁:" + globalLockCode + "已被持有!!");

//说明已经被持有,识别旧值,进行覆盖或更新
String currentValueStr = (String) redisCacheInterface.get(lockKey);
//获得进程ID
String currentValuePID = currentValueStr.substring(0, currentValueStr.lastIndexOf("_"));
//获取原锁预期的释放时间
String endTime = currentValueStr.substring(currentValueStr.indexOf("_") + 1);
logger.info("持有进程[" + currentValuePID + "],预计释放时间:" + ZDateUtils.format(new Date(Long.valueOf(endTime))));


if (currentValuePID.equals(ProcessUtils.getProcessInfo().getPid())) {
//若是本进程持有,则直接刷新时间
logger.info("集群并发锁[" + lockKey + "]为本进程所有,更新值为:" + lockValue);
redisCacheInterface.set(lockKey, lockValue, lockTime);
lockResult = true;

}
else if (System.currentTimeMillis() > Long.parseLong(endTime)) {
//若是锁持有时间已超时,则用getset控制并发,并更换锁的持有者
logger.info("集群并发锁[" + lockKey + "]已超时,value=" + currentValueStr);
String oldValueStr = (String) redisCacheInterface.getSet(lockKey, lockValue);
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
logger.info("集群并发锁[" + lockKey + "]将更新所有者,value=" + lockValue);
redisCacheInterface.set(lockKey, lockValue, lockTime);
lockResult = true;
}
}

//休眠,准备进入下一次轮询
if (!lockResult) {
if (System.currentTimeMillis() - start >= getLockTimeout * 1000L) {
logger.info("集群并发锁:" + globalLockCode + "获取超过了"
+ getLockTimeout + "秒仍未成功,判断为获取锁超时!!");
break;
}
else {
try {
Thread.sleep(tryGetlockInterval * 1000L);
}
catch (InterruptedException e) {
logger.error("休眠异常!!", e);
}
}
}
}
else {
logger.info("集群并发锁[" + lockKey + "]setNX返回成功,值为:" + lockValue);
}
} while (!lockResult);

//2.执行任务
if (lockResult) {
taskAction.ownlockProcess();
}
else {
taskAction.nolockProcess();
}
}

}


/**
* 任务操作接口
*/
public interface TaskAction {

/**
* 成功获取锁后的任务处理操作
*
* @return
*/
Object ownlockProcess();


/**
* 未能获取到拥有锁的处理操作
*
* @return
*/
Object nolockProcess();
}


}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值