Java高并发秒杀解决方案

tech2026-08-10  2

1、把秒杀的商品添加到redis

Goods g = new Goods(); g.setGoodsName("某某笔记本电脑"); g.setPrice(new BigDecimal(9500.00)); g.setStock(50); g.setId(2); //把商品对象存入redis缓存 redisTemplate.boundHashOps(Goods.class.getSimpleName()).put(g.getId(),g); for (int i=0;i<g.getStockCount;i++){ //根据商品的库存,模拟个队列 左进右出 redisTemplate.boundListOps(TbPubliclecture.class.getName()+"_"+id).leftPush(id); }

2、编写业务逻辑

/** *id是商品id userId是用户id */ public String saveOrder(Integer id, String userId) { //0.从用户的set集合中判断用户是否已经抢购过了 redisTemplate.boundSetOps(); Boolean resoult = redisTemplate.boundSetOps(Constant.CONSTANT_USERID_PRBFIX+id).isMember(userId); if (resoult){ return "您已经请购过了,本次秒杀限购一次"; } //1.从队列中获取秒杀商品id id = (Integer) redisTemplate.boundListOps(Constant.CONSTANT_SECKILLGOODS_ID_PRBFIX+id).rightPop(); //2.判断商品是否存在 if (null==id){ //3.商品不存在,或库存《=0,返回失败,提示已售空 return "商品已售空,请选择其他商品"; } //4.将用户放入用户集合内 redisTemplate.boundSetOps(Constant.CONSTANT_USERID_PRBFIX+id).add(userId); //5.创建OrderRecord对象 记录userid和商品id OrderRecord orderRecord = new OrderRecord(id,userId); redisTemplate.boundListOps(OrderRecord.class.getSimpleName()).leftPush(orderRecord); //多线程异步插入数据库订单表 asyncService.executeAsync(); return "秒杀成功"; }

创建一个对象用来储存商品的id和用户的id

@Data public class OrderRecord implements Serializable { //商品的id private Integer id; //用户的id private String userId; }

3、编写一个线程池

@Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Bean public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); // ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //cpu密集型 Integer pollNum = Runtime.getRuntime().availableProcessors(); //io密集型判断你程序中比较消耗io的线程数*2 // 配置核心线程数 executor.setCorePoolSize(6); // 配置最大线程数 executor.setMaxPoolSize(50); // 线程池维护线程所允许的空闲时间 executor.setKeepAliveSeconds(300); // 配置队列大小 executor.setQueueCapacity(10000); // 配置线程池中的线程的名称前缀 executor.setThreadNamePrefix("async-service-"); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 执行初始化 executor.initialize(); return executor; } }

4、秒杀成功,异步处理数据

@Service public class AsyncServiceImpl implements AsyncService { @Autowired private RedisTemplate redisTemplate; @Autowired private RedisSetNxLock redisLock; private String lockKey = "lockKey "; @Override @Async("asyncServiceExecutor") public void executeAsync() { try { OrderRecord orderRecord = (OrderRecord) redisTemplate.boundListOps(OrderRecord.class.getSimpleName()).rightPop(); if (null != orderRecord){ System.out.println("商品id::"+orderRecord.getId()); Goods gg = (Goods) redisTemplate.boundHashOps(Goods.class.getSimpleName()).get(orderRecord.getId()); //生产订单表插入数据库或者redis /** * 这里选择插入到redis里面 * redisTemplate.boundHashOps(订单实体类.class.getSimpleName()).put(orderRecord.getUserId(),订单实体类); */ System.out.println("库存::"+gg.toString()); //如果是单机服务就用synchronized如果是分布式服务可以用分布式锁 加锁redisLock.lock(lockKey,2000,TimeUnit.MILLISECONDS); 解锁 redisLock.unlock(lockKey); synchronized (AsyncServiceImpl.class){ //获取最新的商品信息 gg = (Goods) redisTemplate.boundHashOps(Goods.class.getSimpleName()).get(orderRecord.getId()); //库存 减 1 gg.setStock(gg.getStock()-1); System.out.println("商品剩余库存"+gg.getStock()); //判断库存是否<=0 if (gg.getStock()<=0){ //如果小于等于0 更新数据库 删除秒杀商品的redis缓存 //更新数据库 redisTemplate.boundHashOps(Goods.class.getSimpleName()).delete(orderRecord.getId()); }else{ //如果仍=然有 库存,将减1后的库存更新到redis缓存 redisTemplate.boundHashOps(Goods.class.getSimpleName()).put(orderRecord.getId(),gg); } } } } catch (Exception e) { e.printStackTrace(); } } }

快去使用Jmeter压测试试把

最新回复(0)