zoukankan      html  css  js  c++  java
  • java基于redis事务的秒杀实现

    package com.vian.user.service;
    
    import org.junit.Test;
    import org.springframework.util.CollectionUtils;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    import redis.clients.jedis.Transaction;
    
    import java.io.IOException;
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /** 秒杀测试 */
    public class SecondKillTest {
      @Test
      public void getResult() {
        Jedis jedis = JedisPoolUtil.getJedis();
        String goodsResult = jedis.get("goodsResult:user102");
        System.out.println(goodsResult);
      }
    
      @Test
      public void test() throws IOException, InterruptedException {
        /** 初始化商品 */
        initGoods();
    
        /** 1000线程抢购100个商品 */
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        CountDownLatch count = new CountDownLatch(10000);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
          executorService.execute(new SecondKillHandlder("user" + i));
          count.countDown();
        }
        executorService.shutdown();
        count.await();
        long time = System.currentTimeMillis() - startTime;
        System.out.println("共耗时:" + time + "毫秒");
        // JedisPoolUtil.close();
        System.in.read();
      }
    
      /** 初始化商品数量 */
      private void initGoods() {
        Jedis jedis = JedisPoolUtil.getJedis();
        jedis.set("goods:iphone8", "100"); // 设置100个商品
        JedisPoolUtil.returnRes(jedis);
      }
    
      /** 秒杀处理线程 */
      private static class SecondKillHandlder implements Runnable {
        String goodsKey = "goods:iphone8"; // 监视的key 当前秒杀商品的数量
        Jedis jedis;
        String userName;
    
        public SecondKillHandlder(String userName) {
          this.userName = userName;
        }
    
        @Override
        public void run() {
          while (true) {
            try {
              jedis = JedisPoolUtil.getJedis();
              // watch 监视一个key,当事务执行之前这个key发生了改变,事务会被打断
              jedis.watch(goodsKey);
              int currentGoodsCount = Integer.parseInt(jedis.get(goodsKey)); // 当前剩余商品数量
              if (currentGoodsCount <= 0) {
                System.out.println("商品已抢完," + userName + "---> 抢购失败 XXX");
                break;
              }
              Transaction tran = jedis.multi(); // 开启事务
              tran.incrBy(goodsKey, -1); // 商品数量-1
              List<Object> exec = tran.exec(); // 执行事务
              if (CollectionUtils.isEmpty(exec)) {
                System.out.println(userName + "---> 抢购失败,继续抢购");
                Thread.sleep(1);
              } else {
                exec.forEach(
                    succ -> {
                      String succStr =
                          userName
                              + "===========================> 抢购到第【"
                              + ((100 - currentGoodsCount) + 1)
                              + "】份商品,该商品剩余:"
                              + succ.toString();
                      System.out.println(succStr);
                      jedis.set("goodsResult:" + userName, succStr); // 业务代码,处理抢购成功
                    });
                break;
              }
            } catch (Exception e) {
              e.printStackTrace();
            } finally {
              if (jedis != null) {
                jedis.unwatch();
                JedisPoolUtil.returnRes(jedis);
              }
            }
          }
        }
      }
    
      private static class JedisPoolUtil {
        private static JedisPool pool;
    
        private static void createJedisPool() {
          // 建立连接池配置参数
          JedisPoolConfig config = new JedisPoolConfig();
          // 设置最大连接数
          config.setMaxTotal(100);
          // 设置最大阻塞时间,记住是毫秒数milliseconds
          config.setMaxWaitMillis(1000);
          // 设置空间连接
          config.setMaxIdle(10);
          // 创建连接池
          pool = new JedisPool(config, "192.168.31.201", 6379, 2000, null, 3);
        }
    
        /** 在多线程环境同步初始化 */
        private static synchronized void poolInit() {
          if (pool == null) createJedisPool();
        }
    
        /**
         * 获取一个jedis 对象
         *
         * @return
         */
        public static Jedis getJedis() {
    
          if (pool == null) poolInit();
          return pool.getResource();
        }
    
        /**
         * 归还一个连接
         *
         * @param jedis
         */
        public static void returnRes(Jedis jedis) {
          pool.returnResource(jedis);
        }
    
        public static void close() {
          pool.close();
        }
      }
    }

  • 相关阅读:
    SVN 安装 使用指南
    使用angular-cli快速搭建项目命令
    angular 路由的引用
    c#默认类的修饰符。
    c#
    js改变dom对象样式
    jquery常用函数
    PHP 文件上传
    php 表单代码
    Python 条件语句
  • 原文地址:https://www.cnblogs.com/yangzhenlong/p/9224602.html
Copyright © 2011-2022 走看看