使用redisson 分布式锁 会导致 线程并行执行,在秒杀系统中导致并发下降,此时可以对库存进行分段 如 stockCount = 40 分成四十段,分段的段数和总库存 相关, 用户请求时,随机分配一个段,若获取失败再重试几次,以保证尽可能购买到,详细代码如下
book 不使用锁 本机测试 20000/分钟
bookWithLock:使用分布式锁 但是没有分段 测试结果 1000/分钟
bookWithLock2 使用分布式锁 分段20时测试结果12000/分钟 分段40时测试结果 16000/分钟
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
private static String key = "count";
private static int stockCount = 40;
@Autowired
private RedissonClient redissonClient;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public String book() {
return this.decrementOrder();
}
@Override
public String bookWithLock() {
RLock lock = this.redissonClient.getLock("lock");
Boolean result = false;
try {
result = lock.tryLock(10, TimeUnit.SECONDS);
if (result) {
return this.decrementOrder();
} else {
log.info("==================获取锁失败================");
}
// Boolean result = lock.tryLock(10, TimeUnit.SECONDS);
// if (result) {
// return this.decrementOrder();
// } else {
// log.info("获取锁失败");
// return "获取锁失败";
// }
} catch (Exception e) {
log.error(e.getMessage());
return "预定失败";
} finally {
if (result) {
lock.unlock();
}
}
return "0";
}
private String decrementOrder() {
Long count = Long.valueOf(this.stringRedisTemplate.opsForValue().get(key));
if (count > 0) {
count = this.stringRedisTemplate.opsForValue().decrement(key);
log.info("==================库存还剩{}个================", count);
return String.valueOf(count);
} else {
log.info("库存不足");
}
return "库存不足";
}
@Override
public Long initCount(Long count) {
count = count == null ? 100000 : count;
if (count < stockCount) {
stockCount = 1;
this.stringRedisTemplate.opsForValue().set(key + "_0", count.toString());
} else {
for (int i = 0; i < stockCount; i++) {
this.stringRedisTemplate.opsForValue().set(key + "_" + i, String.valueOf(count / stockCount));
}
if (count % stockCount != 0) {
this.stringRedisTemplate.opsForValue().set(key + "_" + 0, String.valueOf(count / stockCount + count % stockCount));
}
}
this.stringRedisTemplate.opsForValue().set(key, count.toString());
return Long.valueOf(this.stringRedisTemplate.opsForValue().get(key));
}
@Override
public String bookWithLock2() {
RLock lock = null;
Boolean result = false;
//尝试三次
for (int i = 0; i < 3; i++) {
try {
int index = getRandom(stockCount);
lock = this.redissonClient.getLock("lock" + index);
result = lock.tryLock(10, TimeUnit.SECONDS);
if (result) {
String count = decrementOrder2(index);
//如果没获取到(某个段的库存不足)则释放锁
if ("-1".equals(count)) {
lock.unlock();
} else {
return count;
}
}
} catch (Exception ex) {
log.error("执行失败", ex);
} finally {
if (result && lock != null) {
try {
lock.unlock();
} catch (IllegalMonitorStateException e) {
}
}
}
}
log.info("预定失败");
return "0";
}
private String decrementOrder2(Integer index) {
index = index == null ? 0 : index;
//尝试获取次数
String keyTemp = key + "_" + index;
Long count = Long.valueOf(this.stringRedisTemplate.opsForValue().get(keyTemp));
if (count > 0) {
count = this.stringRedisTemplate.opsForValue().decrement(keyTemp);
log.info("==================库存还剩{}个================", count);
return String.valueOf(count);
}
log.info("获取是失败.......");
return "-1";
}
private int getRandom(int count) {
return new Random().nextInt(count);
}
}