业务场景:
业务处理完成之后,需要发送消息(发送短息/或者系统消息),其实此时是不需要强制
发送消息成功的.换句话说,当发送消息失败的时候,我们无需理会,但是不能因为发送消息失败而影响主线程的已有业务逻辑.此时需要新开一个线程,去处理附加的这个发送消息的逻辑;
Executors.newSingleThreadExecutor().execute(() -> {
// 发送系统消息
sendSystemMessage(userId,tenantId);
});
Executors 可以优雅的开启一个线程,并有多种选择,利用线程池处理线程,而且无需用户关心;
当不关心返回值的时候用execute执行.如上就是
当关心返回值的时候用 submit执行,然后用 Future对象通过get()方法获取返回值,可以进行解析或者异常处理等;
=============================================================================
高并发,多实例, 如此就会涉及到多个线程
应用场景 :
高并发场景,如首先校验当前库存数量是否不超过100,然后调用一个新增数量的接口,当有很多人去调用的时候,如果校验库存接口不加锁,那么会导致多个人获取到库存校验的接口都是成功的,然后执行新增数量,那么就会导致库存中的数量出问题;
解决办法 : 我们可以再校验库存的接口上加上@sync 关键字,去让并发,变成串行,这样就不会有问题了
@Synchronized
@Override
public Integer getRemainingChannelNumber(String tenantId) {
// 业务逻辑
}
应用场景 : 高并发下的多实例部署, 例如 服务 A 由与服务器压力过大,目前采用集群部署,通过负载均衡实现,目前有A1 A2
两个实例,在高并发下,如果校验库存接口 两个实例中都有,并且都执行的时候,如果都通过,那么再调用新增数量接口,还是会导致库存数量出问题,那么如何解决呢?
解决办法 :
可以通过分布式锁实现,当获取锁成功的就执行,如果未获取到那么不做操作,这样每次都只会有一个实例执行,这样就又让多实例(多线程),变成了单个实例执行;
@Override
public Integer getRemainingChannelNumber(String tenantId) {
// 获取锁
String simpleUUID = IdUtil.simpleUUID();
String lockKey = RedisConstant.LOCK_KEY + "getRemainingChannelNumber";
Boolean lockState = redisTemplate.opsForValue().setIfAbsent(lockKey
, simpleUUID, 2, TimeUnit.SECONDS);
log.info("获取锁: 状态{} 值:{}", lockState, simpleUUID);
if (!lockState) {
return 0;
}
try {
// 业务逻辑
} finally {// 释放锁
if (simpleUUID.equalsIgnoreCase(redisTemplate.opsForValue().get(lockKey))) {
log.info("释放锁: 值:{}", simpleUUID);
redisTemplate.delete(lockKey);
}
}
}
应用场景 : 高并发下的多实例部署, 例如 服务 A 由与服务器压力过大,目前采用集群部署,通过负载均衡实现,目前有A1 A2
两个实例,在高并发下,如果校验库存接口
两个实例中都有,并且都执行的时候,如果都通过,那么再调用新增数量接口,还是会导致库存数量出问题,一个租户一个锁,锁的自动释放时间为300ms
获取锁时正在被占用,120ms为间隔,最多重试三次,三次获取,均为被占用,提示当前系统繁忙,请稍后重试,那么如何解决呢?
@Override
public Integer getRemainingChannelNumber(String tenantId) {
// 获取锁
String simpleUUID = IdUtil.simpleUUID();
String lockKey = RedisConstant.LOCK_KEY + "getRemainingChannelNumber";
Boolean lockState = redisTemplate.opsForValue().setIfAbsent(lockKey
, simpleUUID, 2, TimeUnit.SECONDS);
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);
try {
// 业务逻辑
} finally {// 释放锁
if (simpleUUID.equalsIgnoreCase(redisTemplate.opsForValue().get(lockKey))) {
log.info("释放锁: 值:{}", simpleUUID);
redisTemplate.delete(lockKey);
}
}
}
本文转自 jimolvxing.blog.csdn.net/article/det…,如有侵权,请联系删除。