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();
}