使用Redis中间件解决商品秒杀活动中出现的超卖问题(使用Java多线程模拟高并发环境)

一、引入Jedis依赖

可以新建Spring或Maven工程,在pom文件中引入Jedis依赖:

 <dependency>
     <groupId>redis.clients</groupId>
     <artifactId>jedis</artifactId>
     <version>2.9.0</version>
 </dependency>

二、Jedis工具类

JedisUtil.java

package com.jake.mallseckill.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisUtil {

    // Redis服务器IP
    private static final String ADDR = "Redis_IP";

    // Redis的端口号
    private static final int PORT = 6379;

    // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
    private static final boolean TEST_ON_BORROW = true;

    // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值是8。
    private static final int MAX_IDLE = 200;

    private static JedisPool jedisPool = null;

    /**
     * 初始化Jedis连接池
     */
    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxIdle(MAX_IDLE);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, ADDR, PORT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Jedis实例
     *
     * @return
     */
    public synchronized static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                Jedis resource = jedisPool.getResource();
                return resource;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放Jedis资源
     *
     * @param jedis
     */
    public static void returnResource(final Jedis jedis) {
        if (jedis != null) {
            // 注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
            jedis.close();
            // 被废弃的方法,使用close即可。
//            jedisPool.returnResource(jedis);
        }
    }

}

三、秒杀测试类(代码模拟多用户+高并发)

RedisSecKiller.java

package com.jake.mallseckill;

import com.jake.mallseckill.utils.JedisUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RedisSecKiller {

    // 模拟用户抢购最大并发数
    private static final int N_THREADS = 5;

    // jedis通过watch方法监控WATCH_KEY,一旦发生改变,事务将失败。
    public static final String WATCH_KEY = "Goods";

    // 商品总数
    private static final int GOODS_NUM = 10;

    // 用户数量
    private static final int USER_NUM = 100;

    public static void main(String[] args) {
        // 创建线程池,模拟N_THREADS位用户同时抢购的过程。
        ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS);
        Jedis jedis = JedisUtil.getJedis();

        // 设置商品总数为10
        jedis.set(WATCH_KEY, String.valueOf(GOODS_NUM));
        jedis.close();

        // 模拟USER_NUM位用户在抢购商品
        for (int i = 0; i < USER_NUM; i++) {
            executorService.execute(new JedisRunnable(UUID.randomUUID().toString()));
//            System.out.println("==============循环分割线===============");
        }

        executorService.shutdown();
    }

}

class JedisRunnable implements Runnable {

    private Jedis jedis = JedisUtil.getJedis();
    private String userId;

    public JedisRunnable(String userId) {
        this.userId = userId;
    }

    @Override
    public void run() {
        try {
            // 事务状态,如果监控的key没有发生改变,那么应该返回OK,事务也可以正常执行。
            jedis.watch(RedisSecKiller.WATCH_KEY);

            // 获取剩余商品数
            int leftGoodsNum = Integer.valueOf(jedis.get(RedisSecKiller.WATCH_KEY));

            // 当剩余商品数大于0时,才进行剩余商品数减1的事务操作。
            if (leftGoodsNum > 0) {
                // 开启jedis事务
                Transaction tx = jedis.multi();

                // 方法一:在事务中对键Goods对应的值做减1操作,此时tx.exec()的返回值的第一个元素是Goods对应的当前值。
                tx.decrBy(RedisSecKiller.WATCH_KEY, 1);

                // 方法二:在事务中设置Goods的值为原值减1,此时tx.exec()的返回值的第一个元素是"OK"。
//                tx.set(RedisSecKiller.WATCH_KEY, String.valueOf(leftGoodsNum - 1));

                // 执行事务,得到返回值。
                List<Object> results = tx.exec();

                // leftGoodsNum比键Goods对应的值大1,因为事务中刚执行了减1操作。
                // 由此可知,在当前事务中,leftGoodsNum与Goods对应的值(真实剩余商品数量)并不同步。
//                System.out.println("剩余商品数量:" + leftGoodsNum);
//                System.out.println("真实剩余商品数量:" + results);

                // results为null或空时,表示并发情况下用户没能抢购到商品,秒杀失败。
                if (results == null || results.isEmpty()) {
                    String failUserInfo = "fail---" + userId;

                    // 此时无法通过results.get(0)获取真实剩余商品数量。
                    String failMsg = "用户" + failUserInfo + ",抢购失败,剩余商品数量:"+ leftGoodsNum +
                            ",但此时无法获取真实剩余商品数量。";
                    System.out.println(failMsg);

                    // 将秒杀失败的用户信息存入Redis。
                    jedis.setnx(failUserInfo, failMsg);
                } else { // 此时tx.exec()事务执行成功,会自动提交事务。
                    for(Object succ : results) {
                        String succUserInfo ="succ" + succ.toString() + "---" + userId;
                        String succMsg= "用户" + succUserInfo + ",抢购成功,当前抢购成功人数:" +
                                (10 - Integer.parseInt(results.get(0).toString())) +
                                ",真实剩余商品数量:" + Integer.parseInt(results.get(0).toString());
                        System.out.println(succMsg);

                        // 将秒杀成功的用户信息存入Redis。
                        jedis.setnx(succUserInfo, succMsg);
                    }
                }
            } else { // 此时库存为0,秒杀活动结束。
                String overUserInfo ="over---" + userId;
                String overMsg = "用户" + overUserInfo + ",商品被抢购完毕,剩余商品数量:" + leftGoodsNum;
                System.out.println(overMsg);

                // 将秒杀活动结束后还在访问秒杀系统的用户信息存入Redis。
                jedis.setnx(overUserInfo, overMsg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JedisUtil.returnResource(jedis);
        }
    }

}

注:关于多线程部分代码的说明

传统的方式是使用new Thread来创建、运行(start)线程,但那样太低效了;使用定长线程池 + ExecutorService的execute方法来创建、运行线程,比前者高效得多。

四、运行结果

4.1 Redis数据插入结果

进入RedisManager -> db0查看
使用Redis中间件解决商品秒杀活动中出现的超卖问题(使用Java多线程模拟高并发环境)
使用Redis中间件解决商品秒杀活动中出现的超卖问题(使用Java多线程模拟高并发环境)

4.2 IDEA控制台输出结果

用户fail---5dd952da-f9fc-4b5f-a8a8-ee9131fc8b51,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---210dd063-2591-465c-9dba-52108ac7e788,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---89f7671e-1e5e-4aa5-8696-c4d6aefa0aa1,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---443c5586-5d29-482a-a8d2-48ddbdfe91ef,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户succ9---32785ae1-87e1-4af4-85ec-8e6753a346f3,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户succ8---58f2b976-c63d-4c80-aa7d-cb895ca434a8,抢购成功,当前抢购成功人数:2,真实剩余商品数量:8
用户fail---d1903f64-6f33-4ffd-87ed-76dd56d85292,抢购失败,剩余商品数量:9,但此时无法获取真实剩余商品数量。
用户fail---70cba697-dc9a-4e98-989a-ef0fe923ef40,抢购失败,剩余商品数量:9,但此时无法获取真实剩余商品数量。
用户succ7---8b0bcc5a-b4b9-4ac0-b718-116de8a16d3e,抢购成功,当前抢购成功人数:3,真实剩余商品数量:7
用户fail---14ff8673-d46e-437d-81b3-d274c6703664,抢购失败,剩余商品数量:7,但此时无法获取真实剩余商品数量。
用户fail---c40b5935-affa-449e-836c-a17c3a6b6f30,抢购失败,剩余商品数量:6,但此时无法获取真实剩余商品数量。
用户succ6---12c5a77f-114e-4bc3-90e7-b8896d1d1c67,抢购成功,当前抢购成功人数:4,真实剩余商品数量:6
用户succ5---9239c9d5-e26f-4da4-9f07-59e59c440465,抢购成功,当前抢购成功人数:5,真实剩余商品数量:5
用户succ4---778eeca9-05c6-42ed-b754-189fd4a02bf7,抢购成功,当前抢购成功人数:6,真实剩余商品数量:4
用户fail---9950c21f-a79a-4138-b2ee-f331aa0f291b,抢购失败,剩余商品数量:5,但此时无法获取真实剩余商品数量。
用户fail---a2cd7477-d762-49ff-96c0-0b9a30616e35,抢购失败,剩余商品数量:4,但此时无法获取真实剩余商品数量。
用户succ3---614ef53d-674b-42cc-ad85-02cd092a8898,抢购成功,当前抢购成功人数:7,真实剩余商品数量:3
用户fail---0322338f-72bf-483f-a844-670e644f18c6,抢购失败,剩余商品数量:3,但此时无法获取真实剩余商品数量。
用户succ2---c06620bc-3f9a-417b-970e-5338682763d0,抢购成功,当前抢购成功人数:8,真实剩余商品数量:2
用户fail---bcbee317-6110-489a-a60c-a8fc658d54d2,抢购失败,剩余商品数量:2,但此时无法获取真实剩余商品数量。
用户fail---52fbd3bc-62f1-4d87-9690-4b43f7312696,抢购失败,剩余商品数量:2,但此时无法获取真实剩余商品数量。
用户succ1---a2d33f13-0ead-480c-8e81-92fa90754d63,抢购成功,当前抢购成功人数:9,真实剩余商品数量:1
用户fail---31b030d6-b250-411e-945e-0cdac212d877,抢购失败,剩余商品数量:1,但此时无法获取真实剩余商品数量。
用户succ0---65e3b93b-66d7-48fc-a93c-c901cfbb10d8,抢购成功,当前抢购成功人数:10,真实剩余商品数量:0
用户over---f9fbc837-439d-44f2-9fd1-728406f45165,商品被抢购完毕,剩余商品数量:0
用户over---fd1fc73c-2986-42b0-a657-f928781c3896,商品被抢购完毕,剩余商品数量:0
用户over---e4e0821e-8056-4eca-bd79-312055b96f65,商品被抢购完毕,剩余商品数量:0
用户over---11dd3cf9-cb7b-424a-8f06-f9dfb344e8f9,商品被抢购完毕,剩余商品数量:0
用户over---227b7df9-5099-40af-8603-1f564c589f05,商品被抢购完毕,剩余商品数量:0
用户over---9d004a87-7901-475b-b85e-06928f863003,商品被抢购完毕,剩余商品数量:0
用户over---c6abeffe-fc03-4d32-850f-4da25caa7bc9,商品被抢购完毕,剩余商品数量:0
用户over---09973975-7a57-4165-94d3-c9f598ee520d,商品被抢购完毕,剩余商品数量:0
用户over---0b690ab6-4823-489d-96e9-73ba380718a9,商品被抢购完毕,剩余商品数量:0
用户over---16cad24a-3ddc-445b-a06d-087afa19a8e4,商品被抢购完毕,剩余商品数量:0
用户over---67680aba-79ee-42bd-b246-d1c6e4230f0f,商品被抢购完毕,剩余商品数量:0
用户over---17effafe-79f8-4e46-a52f-f2b8e2d7d765,商品被抢购完毕,剩余商品数量:0
用户over---582417d3-a6f0-4084-a6b4-98a8358db66c,商品被抢购完毕,剩余商品数量:0
用户over---d282f81b-e032-48a8-b800-7cdb3f89c995,商品被抢购完毕,剩余商品数量:0
用户over---5bd934aa-c476-4be7-92e9-be5781fd28e9,商品被抢购完毕,剩余商品数量:0
用户over---0e0d8083-db94-4385-8ffd-3b44a281e517,商品被抢购完毕,剩余商品数量:0
用户over---a1939cff-6295-40d1-bd05-e5c76aaecfd7,商品被抢购完毕,剩余商品数量:0
用户over---ddb2fba3-b897-4a7a-be02-beed7d8f712a,商品被抢购完毕,剩余商品数量:0
用户over---64f2d6ac-ee45-4cbf-816b-f7272d2bfad8,商品被抢购完毕,剩余商品数量:0
用户over---f6bbdefb-3d9d-44d1-a249-3768eb204642,商品被抢购完毕,剩余商品数量:0
用户over---ab628903-03d0-4445-a025-efc596c9dab3,商品被抢购完毕,剩余商品数量:0
用户over---9f3c569a-b03c-41d1-a5fd-d5f6af0fe2f2,商品被抢购完毕,剩余商品数量:0
用户over---263066ee-7245-47f8-9dcc-eb5cd11569e7,商品被抢购完毕,剩余商品数量:0
用户over---ec9273bf-2a0b-43cc-b5aa-7661413ea868,商品被抢购完毕,剩余商品数量:0
用户over---1d77263c-28d4-46bb-a2d6-cebebf436820,商品被抢购完毕,剩余商品数量:0
用户over---6430b3f2-3cfa-4091-a5aa-9bacd31e72fa,商品被抢购完毕,剩余商品数量:0
用户over---3bf43ac9-25c5-4ddd-b926-f04fe8b4b96a,商品被抢购完毕,剩余商品数量:0
用户over---1d84f400-3d52-4cb8-9e08-e1c6f711a8b9,商品被抢购完毕,剩余商品数量:0
用户over---c202a91d-248a-44c8-8f36-2ac4b1959455,商品被抢购完毕,剩余商品数量:0
用户over---7c719bb8-2878-48e4-8dac-69169e9e520b,商品被抢购完毕,剩余商品数量:0
用户over---fc7e0578-9945-47cb-b3ee-f14bd6b9b156,商品被抢购完毕,剩余商品数量:0
用户over---fff93805-7e11-4236-b627-45d9a83b7c74,商品被抢购完毕,剩余商品数量:0
用户over---7403da53-41ad-4ebc-ae8f-0eddd7b1c499,商品被抢购完毕,剩余商品数量:0
用户over---26fbad73-6437-459b-ae7c-b08c9b921c37,商品被抢购完毕,剩余商品数量:0
用户over---6da51bcb-f467-4b81-811a-56c21aab0f9f,商品被抢购完毕,剩余商品数量:0
用户over---751584d9-d6ff-4fe8-bcf9-915e8af77952,商品被抢购完毕,剩余商品数量:0
用户over---5882e880-6ddb-4af8-a4f9-848f61b1778c,商品被抢购完毕,剩余商品数量:0
用户over---d1d13e94-54ef-4fb2-a62d-131b8c2b4d73,商品被抢购完毕,剩余商品数量:0
用户over---bf76fcd9-2627-441b-999b-daf63da041c5,商品被抢购完毕,剩余商品数量:0
用户over---454d320b-d8cd-41ec-a445-0f538172fde2,商品被抢购完毕,剩余商品数量:0
用户over---821809c3-670e-4000-8641-d301dacbd882,商品被抢购完毕,剩余商品数量:0
用户over---75c4e707-1303-46bd-8b4f-951e166cd8f8,商品被抢购完毕,剩余商品数量:0
用户over---b9a2ff97-3ed8-4ddc-be84-0d95b7af09a1,商品被抢购完毕,剩余商品数量:0
用户over---ecf8e6d3-f74a-48e7-a883-5692385b8ffb,商品被抢购完毕,剩余商品数量:0
用户over---2abc320b-f5a2-4206-9c0b-a7bcdf1070a1,商品被抢购完毕,剩余商品数量:0
用户over---7859ad85-dfbd-4943-8f73-831f6502ab80,商品被抢购完毕,剩余商品数量:0
用户over---3979ec3e-d156-4d35-9b4e-9a6c76796ceb,商品被抢购完毕,剩余商品数量:0
用户over---c6e896f7-b753-4331-8099-87b63a52bdf9,商品被抢购完毕,剩余商品数量:0
用户over---a9231b36-0482-4787-bdeb-265bf31b8299,商品被抢购完毕,剩余商品数量:0
用户over---8f84dc27-f034-49fc-99e9-17258baebe1a,商品被抢购完毕,剩余商品数量:0
用户over---d1650ae9-d62a-4e8f-a793-27d0cdc85f44,商品被抢购完毕,剩余商品数量:0
用户over---34939be5-ad22-4256-99e2-418eb390b406,商品被抢购完毕,剩余商品数量:0
用户over---edbdf692-61b7-4d9c-ad2d-0dcfb2073655,商品被抢购完毕,剩余商品数量:0
用户over---f825d695-4648-46ed-9ad9-98b56ee64180,商品被抢购完毕,剩余商品数量:0
用户over---0849ce35-d0e9-40a5-8bfe-22f54c51de9a,商品被抢购完毕,剩余商品数量:0
用户over---72347a24-86a6-4fd9-b204-66a7ed66bca4,商品被抢购完毕,剩余商品数量:0
用户over---1b32bb40-2305-4b6c-b939-23ad6875010c,商品被抢购完毕,剩余商品数量:0
用户over---5b1d9653-1c7f-4bc8-bb5c-4f5309fecfce,商品被抢购完毕,剩余商品数量:0
用户over---54475f56-9090-436b-9595-154d105268c9,商品被抢购完毕,剩余商品数量:0
用户over---a979df12-1125-4661-b36a-f0ead8139f5c,商品被抢购完毕,剩余商品数量:0
用户over---20a1a07c-1001-4a2f-8a42-00385e3ed554,商品被抢购完毕,剩余商品数量:0
用户over---6218c4da-b2d0-49f7-a11e-3dc901d4b57b,商品被抢购完毕,剩余商品数量:0
用户over---3d3cff93-6fb3-4525-8dab-b52f03427482,商品被抢购完毕,剩余商品数量:0
用户over---9da859c2-07bd-45ac-904b-78af86357477,商品被抢购完毕,剩余商品数量:0
用户over---27752784-c57e-45ce-95c1-c8403ba24ab2,商品被抢购完毕,剩余商品数量:0
用户over---c35cacdc-eb8f-4408-bcd0-4a120e6eef2d,商品被抢购完毕,剩余商品数量:0
用户over---1088459a-b994-4e1d-863f-0b4b68e9cbe7,商品被抢购完毕,剩余商品数量:0
用户over---fb77ee5b-67b5-4331-a86c-d434958ea756,商品被抢购完毕,剩余商品数量:0
用户over---64fb3594-704e-42fc-bd5b-17f4e6ba1ec3,商品被抢购完毕,剩余商品数量:0
用户over---0fda1e7c-6a36-424d-b00a-11ddc82ae95f,商品被抢购完毕,剩余商品数量:0
用户over---e7f351bf-13a7-45c3-9c8c-0f8eb9e2614e,商品被抢购完毕,剩余商品数量:0
用户over---2c1e7263-d307-424c-84b9-6d544d7fbab4,商品被抢购完毕,剩余商品数量:0
用户over---c04de9e8-7ef3-41d4-a7c7-388d07e5e78f,商品被抢购完毕,剩余商品数量:0
用户over---5f1489c3-368d-4a5c-be2a-8a53ef6d275c,商品被抢购完毕,剩余商品数量:0
用户over---709d950b-ba09-4604-8d0c-caac487f449f,商品被抢购完毕,剩余商品数量:0
用户over---ef101b20-b723-445c-af0f-e54c0c9959b3,商品被抢购完毕,剩余商品数量:0

五、有趣的测试

5.1 用户数量小于商品数量,且等于最大并发数

将RedisSecKiller类中的USER_NUM从100改为5,因为此时N_THREADS仍然为5,最大并发数仍为5,即有5个用户同时在抢购10件商品。注意,只要最大并发数大于等于用户数量,就会造成所有用户同时抢购商品(高并发)的情况出现。
运行结果如下:

第一次运行main方法:

用户succ9---7391923d-574d-4fed-b3c1-97384aee812f,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户fail---19793ef1-cced-4ef4-bb80-54fdef84ef41,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---9f003397-99fc-4291-ba04-04e26550698c,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---106db002-612a-480d-b500-570dc227f203,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---3767518c-2b91-4ef1-8494-2d2ac15472b2,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。

第二次运行main方法:

用户succ9---37ae6462-7376-4818-aebf-ec6012353126,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户fail---afd13af2-2c46-442f-b759-7c90bbb784d4,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---4533c4ec-bb52-4d43-b8fe-c44eafdaae18,抢购失败,剩余商品数量:9,但此时无法获取真实剩余商品数量。
用户succ7---eec22de0-4d55-4b64-bdbb-8864c4ddbd88,抢购成功,当前抢购成功人数:3,真实剩余商品数量:7
用户succ8---22be1def-7cf8-4751-808e-2fe18d9f055e,抢购成功,当前抢购成功人数:2,真实剩余商品数量:8

第三次运行main方法:

用户fail---6a0cf86f-264f-4686-8a80-d6a5a2ebf5c0,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---2642bd04-15ab-4ce4-8646-58a61b6141c6,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---7819bf7d-6958-4ae3-a708-2a16a1fa7396,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户succ9---7778f952-e965-4eee-862c-60df05107937,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户fail---3e293589-5e05-4e8a-988c-82d869291a7f,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。

5.2 用户数量小于商品数量,且大于最大并发数

将N_THREADS从5改为3,此时有5名顾客抢购10件商品,但最多只有三名顾客在同一时刻抢购。运行结果:
第一次:

用户succ9---5859a79f-2045-4027-8800-a0cfd464d486,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户fail---76945d54-7b91-4eef-a03c-4d1c5bb5c963,抢购失败,剩余商品数量:9,但此时无法获取真实剩余商品数量。
用户fail---920bd322-4476-4c54-a031-481f29a7d5b2,抢购失败,剩余商品数量:8,但此时无法获取真实剩余商品数量。
用户succ8---ad4315b2-3637-406f-b7a3-be0b9cfd2a1e,抢购成功,当前抢购成功人数:2,真实剩余商品数量:8
用户succ7---d094667c-5cf9-431e-96bc-ab7902b4801b,抢购成功,当前抢购成功人数:3,真实剩余商品数量:7

第二次:

用户succ9---fadb56e5-2ba7-40b5-b572-e9e3e385cc5a,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户fail---247cf4f8-3ce8-4738-a315-5aa4ffe41472,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户fail---1bfd80d4-647d-4711-b9f4-5d6d0c64cbb9,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户succ8---e0f75396-46e7-4689-aa8e-578043df9d12,抢购成功,当前抢购成功人数:2,真实剩余商品数量:8
用户fail---54e87a3f-e992-42b9-bb6d-431d33217ed1,抢购失败,剩余商品数量:9,但此时无法获取真实剩余商品数量。

第三次:

用户fail---bd09d0d7-ac58-43c6-ba74-ce6afe436fc2,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。
用户succ8---a79fb781-d3ae-4ca3-919e-d7cdec9f6227,抢购成功,当前抢购成功人数:2,真实剩余商品数量:8
用户succ9---8efeb302-9646-4f54-b2d3-bb24764cbc5e,抢购成功,当前抢购成功人数:1,真实剩余商品数量:9
用户succ7---04249eef-1304-4976-98c9-2a59fd21c6ca,抢购成功,当前抢购成功人数:3,真实剩余商品数量:7
用户fail---2d3e1846-c6fc-47d0-964d-82a96e5784c6,抢购失败,剩余商品数量:10,但此时无法获取真实剩余商品数量。

5.3 总结

(1)由5.1和5.2对比可知,当用户数量小于商品数量时,并发访问量越大,用户秒杀到商品的成功率就会越低,因为并发量越大,可以进行的秒杀轮数就会越少,能抢购到商品的用户也就越少。
(2)5.1和5.2中的假设其实是不合理的,如果用户数量小于商品数量,供大于求,那也就不应该存在高并发秒杀的概念了,即使此时强行制造秒杀这个概念,但因为库存充足,所以也应该让所有用户都抢购到商品,只是抢到的先后顺序不同而已。
一个真实的网上商城的秒杀活动应该存在如下关系:用户数量(在线)>> 商品数量 > 用户并发数,举例:
由1W台手机等待秒杀,在线等待秒杀活动开始的用户数量为10W,用户并发量为3k。

上一篇:说说怎么写clean code


下一篇:REACTOS(193)与汇编编译器(69)的高人