redis模擬秒殺業務javademo簡單實現
阿新 • • 發佈:2018-12-21
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();
}