Zookeeper分布式锁的尝试使用

通过尝试使用数据库和Redis来实现分布式锁的方式

基于数据库实现的分布式的锁:
一般来说有两种,一种是通过简单的insert方法把一条唯一约束的一条记录插入到数据库的表中,当插入成功后,就默认当前这个线程获取到了分布式的锁,当该线程执行完毕之后,就删除这条记录,释放当前的锁。
在其他线程获取锁的过程中,如果其他的线程想要获取该锁执行插入的sql时,会发生错误,当获取到插入失败的返回值时,就表示当前的线程没有获取到分布式锁,这种方式在分布式场景下有很大的缺点:比如不能防止单点故障,在线程本身获取到锁的同时,其他线程无法获取到锁,因此它一把不可重入的锁,当一个线程没有获取到该锁的时候,无法将该线程分配到某个等待的队列中进行等待,而是让这个获取锁的请求失败,因此它是一把非阻塞的锁,除此之外,当前一个线程在执行完任务之后或因为故障无法释放锁,下一个线程就无法获得锁了,还有这种锁是非公平的锁。

还有另外一种就是基于数据库本身提供的排他锁来实现分布式的锁,利用数据库的InnoDB引擎可以借助它自身的事务功能给我们开启的锁,当一个线程进来时,通过select * from table where … for update可以让innoDB引擎在查询的时候自发给这行记录添加一个排他锁,因此当其他线程查询当前记录的时候,innoDB的排他锁将阻塞当前的查询请求,在上一个线程执行完任务的时候,innoDB将释放当前行的排他锁,阻塞状态中的下一个请求将进来获取新的排他锁执行任务。这种锁因为也是基于数据库的锁,因此也会出现单点故障的风险,因为一般来说只会部署一个数据库,还有这种锁它也是一种不可重入的锁,即在一个线程获取到锁的时候另一个线程无法获取到该锁。它是一种阻塞的锁,当前线程需要锁的时候不是告诉它获取锁失败,取而代之的是阻塞当前的线程,让锁释放后再分配给新的线程,这种锁它并不是一种公平的锁,因为锁的获取完全是随机的。

 public void getDisperselock() throws Exception {
    
            //加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            Connection connection = DriverManager.getConnection(Constent.url,Constent.username,Constent.password);
    
            //开启事务
            connection.setAutoCommit(false);
    
            //让数据库获取排他锁(当列中项有索引的时候使用的是行级锁,否则使用表级锁)
            PreparedStatement preparedStatement = connection.prepareStatement("SELECT identity FROM exclusive WHERE id = ? FOR UPDATE");
            preparedStatement.setInt(1,1);
            boolean execute = preparedStatement.execute();
            if(execute)
            {
                //如果成功拿到锁,则执行任务
                System.out.println("拿到了锁,执行任务");
                Thread.sleep(5000);
                //执行任务完毕后释放锁
                connection.commit();
            }
            else{
                System.out.println("没有拿到锁");
                connection.commit();
           

 }
    }



for (int i = 0; i <3 ; i++) {
            new Thread(new Runnable(){
                @Override
                public void run() {
                    System.out.println(Thread.currentThread());
                    DisperseLock disperseLock = new DisperseLock();
                    try {
                        disperseLock.getDisperselock();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

使用Redis实现分布式的锁:
首先要知道Redis的运行模式,Redis是单进程单线程模式的缓存数据库,当并发访问它时,它会把请求放在队列中一个一个串行处理。
原理:使用redis的setnx key value命令,当要存取的键不存在时,成功设置后返回1,当该键已经存在时,不做任何动作,返回0。当前客户端在执行任务完毕后通过Del key 命令删除该键代表释放该锁。

使用zookeeper实现分布式锁:基于zk实现分布式锁依赖于zk的临时有序节点的特性,基本的原理为:当一个方法进来时,让zk在它的znode目录下生成一个与方法名称相同的目录并创建一个临时的节点,根据当前临时节点的序号,判断当前的临时节点是不是zk中最小的一个,如果是,则让其获取锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值