zookeeper实现分布式锁

1.四种方法保证数据安全

分布式锁 保证分布式领域中共享数据安全问题

1、数据库实现(效率低,不推荐)

2、redis实现(使用redission实现,但是需要考虑思索,释放问题。繁琐一些)

3、Zookeeper实现 (使用临时节点,效率高,失效时间可以控制)

4、Spring Cloud 实现全局锁(内置的)

2.应用场景

在分布式情况,生成全局订单号ID

3.什么是分布式锁

分布式锁一般用在分布式系统或者多个应用中,用来控制同一任务是否执行或者任务的执行顺序。在项目中,部署了多个tomcat应用,在执行定时任务时就会遇到同一任务可能执行多次的情况,我们可以借助分布式锁,保证在同一时间只有一个tomcat应用执行了定时任务

4.实现Zookeeper分布式锁流程

  • 客户端连接上zookeeper,并在指定节点(locks)下创建临时顺序节点node_n
  • 客户端获取locks目录下所有children节点
  • 客户端对子节点按节点自增序号从小到大排序,并判断自己创建的节点是不是序号最小的,若是则获取锁;若不是,则监听比该节点小的那个节点的删除事件
  • 获得子节点变更通知后重复此步骤直至获得锁;
  • 执行业务代码,完成业务流程后,删除对应的子节点释放锁。

5.两种方式实现分布式锁

5.1原生方式

使用java和zk api书写以上逻辑实现分布式锁,操作zookeeper使用的是apache提供的zookeeper的包。通过实现Watch接口,实现process(WatchedEvent event)方法来实施监控,使CountDownLatch来完成监控,在等待锁的时候使用CountDownLatch来计数,等到后进行countDown,停止等待,继续运行。

5.2 Curator方式

Curator是Netflix公司一个开源的zookeeper客户端,在原生API接口上进行了包装,解决了很多ZooKeeper客户端非常底层的细节开发。同时内部实现了诸如Session超时重连,Watcher反复注册等功能,实现了Fluent风格的API接口,是使用最广泛的zookeeper客户端之一。

6.实现锁方法

6.1 普通方法

public class CreateCode {
    private static int count = 0;
    public static String getNumber(){
        try {
            Thread.sleep(300);
        } catch (Exception e) {
            // TODO: handle exception
        }
        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        return simpt.format(new Date()) + "-" + ++count;  //时间戳后面加了 count
    }
}

import com.dyt.utils.CreateCodeUtil;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class OrderService implements Runnable{
    //使用lock锁
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        getNumber();
        //getNumber1();
    }

    /***
     * 第一种方式:synchronized
     * 第二种方式:lock
     */
    
//    public synchronized void getNumber1(){
//        String number = CreateCodeUtil.getNumber();
//        System.out.println(Thread.currentThread().getName()+"num"+number);
//    }
    
    
    public  void getNumber(){
        try {
            lock.lock();
            String number = CreateCodeUtil.getNumber();
            System.out.println(Thread.currentThread().getName()+"num"+number);
        }catch (Exception e){
            
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        OrderService orderService = new OrderService();
        for (int i = 0; i < 100; i++) {
            new Thread(orderService).start();
        }
    }
}

6.2 Curator框架实现分布式锁

  • 导入依赖

     <!--zookeeper的客户端依赖
         org.apache.curator是Netflix公司开源的一个Zookeeper客户端,
         与zookeeper提供的原生客户端相比,Cutrator的抽象层次更高,简化了
         zookeeper客户端的开发量
    -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>4.0.1</version>
    </dependency>
    
  • zkLock类

    package com.dyt.utils;
    
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.framework.recipes.locks.InterProcessMutex;
    import org.apache.curator.retry.RetryNTimes;
    
    import java.util.concurrent.TimeUnit;
    
    public class zkLock {
        private static final String ZK_ADDRESS = "192.168.100.188:2181";
        private static final String ZK_LOCK_PATH = "/zklock/lock0";
    
        private static void zklock(){
            final CuratorFramework client = CuratorFrameworkFactory.newClient(ZK_ADDRESS, new RetryNTimes(10, 5000));
            client.start();
            System.out.println(client.getState());
            System.out.println("zk client start successfully!");
            final InterProcessMutex mutex = new InterProcessMutex(client, ZK_LOCK_PATH);
    
            for (int i = 0; i < 3; i++) {
                Runnable myRunnable = new Runnable() {
                    public void run() {
                        doWithLock(client, mutex);
                    }
                };
                Thread thread = new Thread(myRunnable, "Thread-" + i);
                thread.start();
            }
        }
    
        private static void doWithLock(CuratorFramework client, InterProcessMutex mutex) {
            try {
                String name = Thread.currentThread().getName();
                 /**
                 * acquire(long time, TimeUnit unit)方法,该方法有两个入参分别是超时时间和时间单位。当到达超时时间时会抛出异常终止方法继续阻塞
                 */
                if (mutex.acquire(1, TimeUnit.SECONDS)) {
    
                    System.out.println(name + " hold lock");
    
                    System.out.println(client.getChildren().forPath(ZK_LOCK_PATH));
    
                    Thread.sleep(5000L);
                    System.out.println(name + " release lock");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    mutex.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        
        
        public static void main(String[] args) {
            zkLock.zklock();
        }
        
    }
    
  • 在这里插入图片描述

  • 启动三个线程去获取锁,线程1获取到锁sleep5秒,超时时间设置为1s,线程0和线程2阻塞等待1s后,便会抛出异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值