1. 程式人生 > >redis模擬秒殺業務javademo簡單實現

redis模擬秒殺業務javademo簡單實現

redis實現秒殺javademo實現

WATCH命令介紹

監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。

MULTI命令介紹

標記一個事務塊的開始。

事務塊內的多條命令會按照先後順序被放進一個隊列當中,最後由 EXEC 命令原子性(atomic)地執行。

EXEC命令介紹

執行所有事物塊內的命令

假如某個(或某些) key 正處於 WATCH 命令的監視之下,且事務塊中有和這個(或這些) key 相關的命令,那麼 EXEC 命令只在這個(或這些) key 沒有被其他命令所改動的情況下執行並生效,否則該事務被打斷(abort)。

思路

先通過WATCH命令監控goods,此後又將set命令包圍在事務中,這樣就可以有效的保證每個連線在執行EXEC之前,如果當前連接獲取的goods的值被其它連線的客戶端修改,那麼當前連線的EXEC命令將執行失敗。這樣呼叫者在判斷返回值後就可以獲悉val是否被重新設定成功。

我們看下虛擬碼

WATCH goods

val = val + 1

MULTI

SET goods $val

EXEC

廢話不多說,上程式碼

/**
 *
初始化商品
 */

 private void initGoogs() {
    Jedis jedis = RedisUtil.getJedis

();
    String watchKey = "goods";
   
int goodsCount = 20;
    jedis.set(watchKey, String.valueOf(goodsCount));

 }

/**
 * 模擬多個使用者搶購
 */
private void secKill() {
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    int clientNum = 1000;// 模擬客戶數目
    for (int i = 0; i < clientNum; i++) {
        cachedThreadPool.execute(new customerThread(i));
    }
    cachedThreadPool.shutdown();
    while(true){
        if(cachedThreadPool.isTerminated()){
            System.out.println("所有的執行緒都結束了!");
            break;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 列印秒殺結果
 */
public void print() {
    Jedis jedis = RedisUtil.getJedis();
    Set<String> set = jedis.smembers("client");
    int i = 1;
    for (String value : set) {
        System.out.println("第" + i++ + "個搶到商品," + value + " ");
    } 
class customerThread implements Runnable{
    // 監視的商品
    String watchKey = "goods";
    String clientKey = "client";
    String customerName;

    customerThread(int num) {
        this.customerName = "編號:" + num;
    }

    public void run() {
        try {
            //隨機暫停
            Thread.sleep((int)(Math.random()*5000));
        } catch (InterruptedException e) {
        }
        while (true) {
            System.out.println(customerName + "開始搶商品!");
            Jedis jedis = RedisUtil.getJedis();
            try{
                jedis.watch(watchKey);
                int goodsCount = Integer.parseInt(jedis.get(watchKey));
                if(goodsCount > 0) {
                    //開啟事物
                    Transaction transaction = jedis.multi();
                    transaction.set(watchKey, String.valueOf(goodsCount - 1));
                    //提交事物
                    List<Object> result =  transaction.exec();
                    if(!result.isEmpty()) {
                        jedis.sadd(clientKey, customerName);//
                        System.out.println("顧客" + customerName + "搶到了¥¥¥¥");
                        break;
                    } else{
                        System.out.println("顧客" + customerName + "沒搶到!!!!");
                    }
                } else {
                    System.out.println("顧客" + customerName + "沒貨了!!!!");
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                jedis.unwatch();
                RedisUtil.returnResource(jedis);
            }
        }
    }
 }
@Test
public void test() {
    initGoogs();
    secKill();
    print();
}