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 "商品已售罄";
        }
    }
}

对比两次的结果:

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

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);

    //  后续执行

    //  返回结果
}

Original: https://www.cnblogs.com/cjsblog/p/16438567.html
Author: 废物大师兄
Title: Redis+Lua实现简易的秒杀抢购

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/584872/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球