一、引入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查看

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。

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

  1. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  2. 利用redis实现分布式事务锁,解决高并发环境下库存扣减

    利用redis实现分布式事务锁,解决高并发环境下库存扣减   问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...

  3. redis解决商品秒杀问题

    博主最近在项目中遇到了抢购问题!现在分享下.抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖" ...

  4. 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法

    数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...

  5. 项目中遇到的超卖问题及解决办法(使用go做测试工具)

    超卖问题:在一个很短的时间内,Mysql的数据状态在 取出,比较,提交,或修改中,另外一个进程访问数据导致的超卖问题. 案例: 1.前端没有做限制,如果用户连续点击签到,那么会有多条数据发送到后端,如 ...

  6. 记一次项目中解决 -- 并发减库存超卖问题过程(Java)

    起因:项目中要做预约功能,首先每天的余票都是有上限的,自然不能出现超卖的情况 基于我们项目是单体分布式的springcloud部署,我想了下 第一种方法,直接mysql加行锁,要update这条库存数 ...

  7. web开发中的两把锁之数据库锁:(高并发--乐观锁、悲观锁)

    这篇文章讲了 1.同步异步概念(消去很多疑惑),同步就是一件事一件事的做:sychronized就是保证线程一个一个的执行. 2.我们需要明白,锁机制有两个层面,一种是代码层次上的,如Java中的同步 ...

  8. 秒杀怎么样才可以防止超卖?基于mysql的事务和锁实现

    Reference:  http://blog.ruaby.com/?p=256 并发事务处理带来的问题? 相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从 ...

  9. 高并发环境下,Redisson实现redis分布式锁

    原文:http://tlzl0526-gmail-com.iteye.com/blog/2378853 在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好, ...

随机推荐

  1. Python 的经典设计格言,格言来源于 Python 但不限于 Python

    The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Si ...

  2. Linux学习笔记:安装python

    一般linux自带python2,如果需要python3以上版本,可以不需要卸载自带的python2,二者可以共存.只需要配置相应的环境变量即可. 具体回答可以参考这篇文章 https://stack ...

  3. cannot open shared object file: No such file or directory解决方法

  4. 创建Gitblit本地服务器(For windows )01

    1.先下载gitblit  貌似需要FQ,百度云链接https://pan.baidu.com/s/1WUtBswj5TkFFcd_hiFFCcw,提取码: xr9n .因为gitblit是基于jav ...

  5. Java: 集合类详解

    0.参考文献 http://blog.csdn.net/liulin_good/article/details/6213815 1.java集合类图 1.1 1.2 上述类图中,实线边框的是实现类,比 ...

  6. BERT(Bidirectional Encoder Representations from Transformers)

    BERT的新语言表示模型,它代表Transformer的双向编码器表示.与最近的其他语言表示模型不同,BERT旨在通过联合调节所有层中的上下文来预先训练深度双向表示.因此,预训练的BERT表示可以通过 ...

  7. AlphaGo原理浅析

    一.PolicyNetwork(走棋网络) 首先来讲一下走棋网络.我们都知道,围棋的棋盘上有19条纵横交错的线总共构成361个交叉点,状态空间非常大,是不可能用暴力穷举的方式来模拟下棋的.但是我们可以 ...

  8. Python 协程 61

    什么是协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程的特点 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到 ...

  9. [转]找到MySQL发生swap的原因

    背景: 最近遇到了一个郁闷的问题:明明OS还有大量的空闲内存,可是却发生了SWAP,百思不得其解.先看下SWAP是干嘛的,了解下它的背景知识.在Linux下,SWAP的作用类似Windows系统下的“ ...

  10. 【慕课网实战】五、以慕课网日志分析为例 进入大数据 Spark SQL 的世界

    提交Spark Application到环境中运行spark-submit \--name SQLContextApp \--class com.imooc.spark.SQLContextApp \ ...