Zookeeper---分布式锁

天涯浪子 提交于 2019-12-14 07:43:04

为什么用Zk实现分布式锁?
因为ZK自身的机制,创建节点的四种种类和每个节点的唯一性,使它适用于做分布式锁。

ZK分布式锁的羊群效应
所有的客户端都尝试去创建一个临时节点,但是只会有一个创建成功,其他的客户端去监听这个节点的变化。一旦这个临时节点释放,zk会通知监听这些节点的客户端,由于监听这个节点的数量多,会来回造成大量的网络开销,影响ZK的性能。这就是所谓的zk的分布式锁的羊群效应,这种方法是不可取的。
最理想的状态是什么?肯定是一个节点的变化去通知一个节点,所以,为了解决羊群效应的,所有的客户端去创建一个临时节点的时候,每个客户端都去创建一个临时顺序节点,大的节点监听比自己小的节点的变化。最小的节点先获得锁,操作完成释放锁,然后通知监听自己的节点去获取锁,依次类推。这样就可以解决羊群效应。

我们用Curator这个开源框架实现ZK的分布式锁。
先引入Curator包。

<dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-recipes</artifactId>
      <version>2.9.0</version>
</dependency>

共享资源:

public class Phone {
    private int number = 5;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    //订购
    public static void buy(Phone phone){
        System.out.println("【" + Thread.currentThread().getName() + "】开始抢购");

        //获取剩余手机数量
        int currentNumber = phone.getNumber();
        if (currentNumber <= 0){
            System.out.println("抢购已结束,下次再来吧");
            phone.setNumber(-1);
        }else {
            System.out.println("剩余手机数量:"+currentNumber+"个!");
            currentNumber--;
            phone.setNumber(currentNumber);
            System.out.println("【" + Thread.currentThread().getName() + "】开始抢购");
        }

        System.out.println("------------------------------------------------------");
    }
    //支付
    public static void pay(){
        System.out.println("【" + Thread.currentThread().getName() + "】开始付款");
        System.out.println("【" + Thread.currentThread().getName() + "】付款完成");
        System.out.println("*****************************************************");
    }
}

分布式锁代码的实现

public static void buyPhone(){
        Phone phone = new Phone();
        //可重入锁
        InterProcessMutex interProcessMutex = new InterProcessMutex(zkClient,"/buy_phone");

        for(int i= 0;i<100;i++){
            new Thread(()->{
                try{
                    //增加第一把锁
                    interProcessMutex.acquire();
                    System.out.println(Thread.currentThread().getName() + "获得第一把锁");
                    //完成抢购
                    Phone.buy(phone);

                    if(phone.getNumber()>=0){
                        interProcessMutex.acquire();
                        System.out.println(Thread.currentThread().getName() + "获得第二把锁");
                        //完成付款
                        Phone.pay();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                        try{
                            interProcessMutex.release();
                            if(phone.getNumber()>=0){
                                interProcessMutex.release();
                            }
                        }catch (Exception e){
                            e.printStackTrace();
                        }

                }

            }).start();
        }
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!