package com.test; import java.io.IOException; import java.util.List; import java.util.concurrent.CyclicBarrier; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; public class Main { public static void main(String[] args) throws IOException, KeeperException, InterruptedException { ZooKeeper zk = new ZooKeeper("127.0.0.1", 2000, null); Stat st = zk.exists("/goods", false); if (st == null) { zk.create("/goods", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } String[] goods = { "iPhone6s", "小米移动电源" }; for (String g : goods) { zk.create("/goods/" + g, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); } int threadCount = 5; CyclicBarrier cb = new CyclicBarrier(threadCount); // 为了更好地表示并发,这里用了CyclicBarrier类 for (int i = 0; i < threadCount; i++) { // 用多线程摸您多用户 new Thread(new Thread1(cb)).start(); } System.in.read(); } static class Thread1 implements Runnable { ZooKeeper zk = null; CyclicBarrier cb; // 是否还没有抢过商品 boolean isNotGet = true; public Thread1(CyclicBarrier cb) { this.cb = cb; } private void snatchGoods() throws Exception { // 获取商品库存 List<String> goodsList = zk.getChildren("/goods", true);// 获取商品列表并监控变化,如果在和其它用户抢购同一个商品时没抢到的情况下可再次监控其它商品 if (goodsList.isEmpty()) { // 商品库存为空,表示商品抢光了 System.out.println(Thread.currentThread().getName() + "没抢到商品"); } else { // 获取第一个商品 String goods = goodsList.get(0); try { // 从内存中删除商品节点,表示抢购,如果删除失败,就表示没抢到这个商品,并进入到下面的catch块中 zk.delete("/goods/" + goods, -1); // 限制每个用户只能抢购一件商品,设置false表示已经抢购过了 isNotGet = false; System.out.println(Thread.currentThread().getName() + "抢到了" + goods); } catch (Exception e) { } } } @Override public void run() { try { zk = new ZooKeeper("127.0.0.1:2181", 2000, new Watcher() { @Override public void process(WatchedEvent event) { try { EventType type = event.getType(); if (isNotGet) { if (type == EventType.None) { // 用户第一次访问,则立即执行商品的抢购 snatchGoods(); } else if (type == EventType.NodeChildrenChanged) { // 抢购一件商品失败后,再抢购另一件商品 snatchGoods(); } } } catch (Exception e) { System.out.println(e.getMessage()); } } }); } catch (Exception e) { e.printStackTrace(); } } } }
- 使用多线程模拟多用户抢购
- 用户第一次访问,则立即执行商品的抢购
- 抢购一件商品失败后,再抢购另一件商品
- 商品库存为空,表示商品抢光了
zookeeper实现商品秒杀抢购:
秒杀活动是一些购物平台推出的集中人气的活动,一般商品数量很少,价格很便宜,限定开始购买的时间,会在以秒为单位的时间内被购买一空。比如原价千元甚至万元的商品以一元的价格出售,但数量只有一件,在某天的某个时间开始出售,这就造成很多人去抢这一件商品。
获取商品列表并监控变化,如果在和其它用户抢购同一个商品时没抢到的情况下可再次监控其它商品
抢购一件商品失败后,再抢购另一件商品
运行多次,打印出如下结果:
Thread-4-EventThread抢到了iPhone6s Thread-1-EventThread抢到了小米移动电源 Thread-2-EventThread没抢到商品 Thread-3-EventThread没抢到商品 Thread-0-EventThread没抢到商品
Thread-3-EventThread抢到了iPhone6s
Thread-2-EventThread抢到了小米移动电源
Thread-4-EventThread没抢到商品
Thread-1-EventThread没抢到商品
Thread-0-EventThread没抢到商品
Thread-0-EventThread抢到了iPhone6s
Thread-3-EventThread抢到了小米移动电源
Thread-4-EventThread没抢到商品
Thread-2-EventThread没抢到商品
Thread-1-EventThread没抢到商品
Thread-2-EventThread抢到了iPhone6s
Thread-4-EventThread抢到了小米移动电源
Thread-0-EventThread没抢到商品
Thread-3-EventThread没抢到商品
Thread-1-EventThread没抢到商品
可以看到,两件商品,多个线程并发抢购,总是只有两个线程分别抢到不同的商品。