• 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);
    
        //  后续执行
    
        //  返回结果
    }
  • 相关阅读:
    看我这篇就够了!os.system批量执行py文件!!!!
    关于python文件显示为空白文件图标的解决办法
    Python Windows下整体项目环境迁移
    python + selenium + firefox 自定义配置文件启动浏览器
    Selenium OSError: [WinError 193] %1 不是有效的 Win32 应用程序
    redis安装后,输入redis-server.exe redis.windows.conf无法启动
    MongoDB安装
    安装tesserocr pillow报错
    【流水账】2021-07-09 Day-29
    【流水账】2021-07-08 Day-28
  • 原文地址:https://www.cnblogs.com/cjsblog/p/16438567.html
Copyright © 2020-2023  润新知