信号量机制
使用java.util.concurrent下的semaphore类作为信号量
用途
设置一个信号量Map,需要时从此Map中get(特定ID)信号量来控制访问请求数量,以实现对单个请求的流量控制,增加系统稳定性。
用法
- 编写SemaphoreManager实现对信号量统一管理
- 声明信号量Map Map<Long, Semaphore> semaphoreMap
- 编写初始化信号量的方法init(args...),设置初始大小的信号量Map
- 编写获取信号量的方法(getSemaphore(args...))、创建信号量方法(createSemaphore(size)),创建信号量时,直接new Semaphore(size)对象即可。
使用时可以在项目初始化方法中、aop中、或相应业务代码中引入使用。
以下是代码部分
SemaphoreManager
java
@Component
public class SemaphoreManager {
@Resource
private DisConfig disConfig;
private Map<Long, Semaphore> semaphoreMap = new HashMap<>();
/**
* 初始化信号量对象
*
* @param list 对象信息列表
*/
public void init(Collection<ObjectDO> list) {
if (CollectionUtils.isEmpty(list)) {
return;
}
// 为每个第三方系统生成一个信号量对象
for (ObjectDO objectDO: list) {
// 创建信号量对象
semaphoreMap.put(objectDO.getId(), createSemaphore(objectDO.getMaxConcurrentNum()));
}
}
/**
* 获取信号量对象
*
* @return 信号量对象
*/
public Semaphore getSemaphore() {
ObjectContext context = ContextManager.getContext();
if (context == null) {
return null;
}
return getSemaphore(context.getObjectId(), context.getMaxConcurrentNum());
}
/**
* 获取信号量对象
*
* @param objectId 对象ID
* @param maxConcurrentNum 最大并发数
* @return 信号量对象
*/
private Semaphore getSemaphore(Long objectId, Integer maxConcurrentNum) {
if (semaphoreMap == null) {
return null;
}
// 获取当前对接通道的信号量对象
Semaphore semaphore = semaphoreMap.get(objectId);
if (semaphore != null) {
return semaphore;
}
synchronized (objectId.toString().intern()) {
semaphore = createSemaphore(maxConcurrentNum);
semaphoreMap.put(objectId, semaphore);
}
return semaphore;
}
/**
* 创建信号量对象
*
* @param maxConcurrentNum 最大并发数
* @return 信号量对象
*/
private Semaphore createSemaphore(Integer maxConcurrentNum) {
// 如果DB中没有设置则使用disconf中设置的默认值
if (maxConcurrentNum == null || maxConcurrentNum == 0) {
maxConcurrentNum = disConfig.getMaxSemp();
}
if (maxConcurrentNum == 0) {
maxConcurrentNum = 100;
}
return new Semaphore(maxConcurrentNum);
}
}
代码使用实践
java
Boolean isAcq = false;
// 获取信号量对象
semaphore = semaphoreManager.getSemaphore();
if (semaphore != null) {
// 获取信号量
isAcq = semaphore.tryAcquire();
// 获取失败时说明请求量过大, 直接返回异常信息
AssertUtil.isTrue(isAcq, EnumResultCode.THIRD_SLOWLY);
}