zookeeper学习之wait,notify,notifyall感想

本文介绍如何利用ZooKeeper实现线程间的同步处理。通过创建临时节点并结合watcher机制,确保多个线程能够按需同时开始及结束任务。示例代码展示了四个线程如何实现同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:概念

1.如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。

2.如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。

3.如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

二:结合zookeeper,协调不同任务之间的同步处理

思想:1.注册watcher,watch中唤醒持有对象锁的线程

    2.进入一个任务的时候,在zookeeper上创建一个节点,触发watcher,唤醒3中阻塞的线程

    3.循环看当前子节点数是否达到任务数,若达到,退出循环,若没有,则阻塞当前线程

代码:

public class Barrier implements Watcher {

    private static final String addr = "localhost:2181";
    private ZooKeeper           zk   = null;
    private Integer             mutex;
    private int                 size = 0;
    private String              root;

    public Barrier(String root, int size) {
        this.root = root;
        this.size = size;

        try {
            zk = new ZooKeeper(addr, 10 * 1000, this);
            mutex = new Integer(-1);
            if (zk.exists("/test", false) == null) {
                zk.create("/test", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            Stat s = zk.exists(root, false);
            if (s == null) {
                zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public synchronized void process(WatchedEvent event) {
        synchronized (mutex) {
            mutex.notify();
            System.out.println("------1111");
        }
    }

    /**
     * 以此例子中的四个线程为例<br>
     * 线程1进来时,发现节点数小于任务数,于是持有对象mutex的锁并等待<br>
     * 线程2进来时,因创建子节点,触发zookeeper watcher,所以会唤醒持有mutex锁的线程,故而线程1被唤醒<br>
     * 然后线程1,2都会去判断节点数有没有达到任务数,发现没有达到,于是线程1,2持有对象mutex的锁并等待。。。<br>
     * 直到节点数等于任务数,唤醒线程,流程继续往下走
     * 
     * @param name
     * @return
     * @throws Exception
     */
    public boolean enter(String name) throws Exception {
        zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        while (true) {
            synchronized (mutex) {
                List<String> list = zk.getChildren(root, true);
                if (list.size() < size) {
                    System.out.println("------2222=========" + Thread.currentThread().getName());
                    mutex.wait();
                } else {
                    return true;
                }
            }
        }
    }

    public boolean leave(String name) throws KeeperException, InterruptedException {
        zk.delete(root + "/" + name, 0);
        while (true) {
            synchronized (mutex) {
                List<String> list = zk.getChildren(root, true);
                if (list.size() > 0) {
                    mutex.wait();
                } else {
                    return true;
                }
            }
        }
    }

}

public class BarrierTest {
    public static void main(String args[]) throws Exception {
        for (int i = 0; i < 4; i++) {
            Process p = new Process("Thread-" + i, new Barrier("/test/barrier", 4));
            p.start();
        }
    }
}

class Process extends Thread {

    private String  name;
    private Barrier barrier;

    public Process(String name, Barrier barrier) {
        this.name = name;
        this.barrier = barrier;
    }

    @Override
    public void run() {
        try {
            barrier.enter(name);
            System.out.println(name + " enter");
            Thread.sleep(1000 + new Random().nextInt(2000));
            barrier.leave(name);
            System.out.println(name + " leave");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


三,从执行结果看,虽然4个线程启动并不在同一时间,但是同一时间执行任务,可能每个任务执行时间的长短不一样,但是上述例子也控制了一起结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值