springboot单机秒杀之queue队列
一:
queue队列,类似水管,水从入口进从水龙头出,水龙头要一直着水就会出来,没有水就会等水出来。
所以我们用到两个方法,
添加和取值。
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
put 添加一个元素 如果队列满,则阻塞
因为我们是秒杀,我们指定队列长度后不需要它阻塞。队列长度就是请求的成功数。
poll 移除并返问队列头部的元素 如果队列为空,则返回null
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
take 移除并返回队列头部的元素 如果队列为空,则阻塞
我们用take一直阻塞。
2:
/** * 队列工具类 * * @author jiang */ public class QueueUtil { /** * 初始化有界队列队列 */ private static final LinkedBlockingQueue<String> LINKED_BLOCKING_QUEUE = new LinkedBlockingQueue<String>(100); public static boolean add(String killId) { try { LINKED_BLOCKING_QUEUE.add(killId); return true; } catch (Exception e) { return false; } } public static Optional<String> take() { String killId = null; try { killId = LINKED_BLOCKING_QUEUE.take(); } catch (InterruptedException e) { e.printStackTrace(); } return Optional.ofNullable(killId); }
@GetMapping("/startKill2") public R startKill2(String killId) { if (QueueUtil.add(killId)) { return R.ok(); } return R.error(); }
** * 项目启动时加载 */ @Component @Slf4j public class MyApplicationRunner implements ApplicationRunner { @Autowired private ISeckillService seckillService; @Override public void run(ApplicationArguments args) throws Exception { log.info("项目初始化加载"); while (true) { Optional<String> killId = QueueUtil.take(); killId.ifPresent(s -> seckillService.startKill(s)); } } }
@Override @Transactional(rollbackFor = Exception.class) public R startKill(String killId) { Seckill seckill = this.getOne(new LambdaQueryWrapper<Seckill>().eq(Seckill::getSeckillId, killId)); int number = seckill.getNumber(); if (number > 0) { Seckill seckill1 = seckill.setNumber(--number); this.update(seckill1, new LambdaQueryWrapper<Seckill>().eq(Seckill::getSeckillId, seckill.getSeckillId())); SuccessKilled successKilled = new SuccessKilled(); successKilled.setCreateTime(new Date()); successKilled.setSeckillId(Long.parseLong(killId)); successKilled.setState(0); successKilledMapper.insert(successKilled); return R.ok(); } return R.error("没有了!"); }