• Redis+Lua实现简易的秒杀抢购


    1  商品抢购

    主要逻辑是:减库存,记录抢购成功的用户

    @RestController
    public class DemoController {
    
        @Resource
        private StringRedisTemplate stringRedisTemplate;
    
        private static final String GOODS_STOCK_KEY = "goods:001";  //  秒杀商品库存
        private static final String GOODS_USER_KEY = "users:001";   //  抢购成功的用户列表
    
        /**
         * 在不加锁的情况下,会发生超卖
         */
        @GetMapping("/seckill")
        public String seckill() {
            int userId = (int) (Math.random() * 1000);
    
            ValueOperations valueOps = stringRedisTemplate.opsForValue();
            ListOperations listOps = stringRedisTemplate.opsForList();
    
            int stock = Integer.parseInt(valueOps.get(GOODS_STOCK_KEY));
    
            if (stock > 0) {
                valueOps.decrement(GOODS_STOCK_KEY);
                listOps.leftPush(GOODS_USER_KEY, String.valueOf(userId));
                return "抢购成功";
            } else {
                return "商品已售罄";
            }
        }
    
        /**
         * 将多个命令打包成一个原子操作,利用redis单线程执行命令的特性,在不加锁的情况下避免了资源竞争
         */
        @GetMapping("/seckill_lua")
        public String seckill_lua() {
            int userId = (int) (Math.random() * 1000);
    
            String script = "if tonumber(redis.call('get', KEYS[1])) > 0 then " +
                    "redis.call('decr', KEYS[1]); " +
                    "redis.call('lpush', KEYS[2], ARGV[1]); " +
                    "return 1; " +
                    "else " +
                    "return 0; " +
                    "end; ";
    
            DefaultRedisScript redisScript = new DefaultRedisScript();
            redisScript.setResultType(Long.class);
            redisScript.setScriptText(script);
    
            List keyList = Arrays.asList(GOODS_STOCK_KEY, GOODS_USER_KEY);
    
            Long result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(userId));
    
            if (result == 1) {
                return "抢购成功";
            } else {
                return "商品已售罄";
            }
        }
    }

    对比两次的结果:

    2  多线程处理Excel导入

    /**
     * 多线程处理Excel导入
     *
     * PS:
     *  Executors返回的线程池对象的弊端如下:
     *  (1) FixedThreadPool和SingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
     *  (2) CachedThreadPool: 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
     */
    @PostMapping
    public void excelImport() throws InterruptedException {
        //  待处理的数据(比如:从Excel中读取的数据) 
        List dataList = new ArrayList();
    
        //  多线程处理
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        CountDownLatch countDownLatch = new CountDownLatch(dataList.size());
        for (Object obj : dataList) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
    
                    } catch (Exception ex) {
    
                    } finally {
                       countDownLatch.countDown();
                    }
                }
            });
        }
    
        countDownLatch.await(30, TimeUnit.SECONDS);
    
        //  后续执行
    
        //  返回结果
    }
  • 相关阅读:
    软件工程概论作业二 电梯调度思路 信1205班 刘权毅 董文轩
    软件工程概论作业一 信1205班 20122561 董文轩
    团队开发第三天(董文轩,苏康奖,常晓杨,刘权毅,刘梦辉,刘若凡)
    软件工程概论作业三 信1205班 董文轩 刘权毅
    IDEA 搭建spring+maven+mybatis+mysql+junit+log4j2
    什么时候需要实现序列化Serializable
    IDEA如何查看maven依赖冲突
    Docker for windows : 安装linux
    Mybatis 分页
    POI java操作OFFICE产品
  • 原文地址:https://www.cnblogs.com/cjsblog/p/16438567.html
Copyright © 2020-2023  润新知