• 分布式锁


    分布式锁

    为了保证一个方法或属性在高并发情况下的同一时间只能被一个线程访问,在单机部署的情况下,可以使用ReentrantLock或Synchronized进行互斥控制。随着发展,单机部署的系统已经不能满足业务的需要,越来越多的系统进化成分布式集群系统,原本在单机运行的锁控制已经不能实现“一个方法或属性在高并发情况下的同一时间只能被一个线程访问”的控制,要在分布式系统中实现在单机中的控制效果就必须使用分布式锁。

    Redis实现方式

    加入依赖

            <!--redisson分布式锁-->
            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>3.6.5</version>
            </dependency>
    

    配置Redisson bean

        @Bean
        public Redisson redisson(){
            //单机模式
            Config config = new Config();
    //        config.useClusterServers().addNodeAddress("","","");//集群模式
            config.useSingleServer().setAddress("redis://192.168.86.126:6379");
            return (Redisson) Redisson.create(config);
        }
    

    实现

    		//业务代码加redis分布式锁
            String lockKey = "redis-lock-key";
            RLock rlock = redisson.getLock(lockKey);
    
            //加锁并设置超时时间,自动续幂
            rlock.lock(30, TimeUnit.SECONDS);
            try {
                //加锁业务代码
                ……
    
            } finally {
                //解锁
                rlock.unlock();
            }
    
    

    Zookeeper实现

    加入依赖

     		<!--zookeeper的jar依赖包-->
            <dependency>
                <groupId>com.101tec</groupId>
                <artifactId>zkclient</artifactId>
                <version>0.11</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    

    Lock接口

    public interface Lock {
    
        void lock() throws Exception;
    
        void unlock() throws Exception;
    }
    
    

    写一个抽象类AbstractZookeeperLock实现加锁和解锁

    public abstract class AbstractZookeeperLock implements Lock {
    
        protected String lock;
    
        protected String zkAddress = "localhost:2181";
    
        protected ZkClient zkClient = new ZkClient(zkAddress);
    
        @Override
        public final void lock() throws Exception {
    
            //尝试获取锁
            if (tryLock()) {
                //拿到锁
                System.out.println("获取锁成功...");
            } else {
                //尝试获取锁未成功,等待获取锁,阻塞
                // 如果此处已经不阻塞了,那么可以继续执行下面的代码
                waitLock();
                //阻塞结束,继续获取锁
                lock();
            }
        }
    
    
        @Override
        public final void unlock() throws Exception {
            //临时节点:临时存储,当客户端的链接与zookeeper断开后,临时节点自动删除
            //关闭链接就解锁了
            if (zkClient != null) {
    //            zkClient.delete("/path/xxx");
                zkClient.close();
                System.out.println("解锁成功...");
            }
            //持久化节点:永久在zookeeper上
        }
    
        protected abstract boolean tryLock();
    
        protected abstract void waitLock();
    }
    

    具体使用类实现尝试获取锁和等待获取锁

    public class ZookeeperDistributedLock extends AbstractZookeeperLock {
    
        private CountDownLatch countDownLatch;
    
        public ZookeeperDistributedLock(String lockName) {
            lock = lockName;
        }
    
        //尝试获取锁
        @Override
        protected boolean tryLock() {
    
            try {
                //创建一个临时节点
                zkClient.createEphemeral(lock);
                //获取锁成功
                return true;
            } catch (Exception e) {
                //获取锁失败
                return false;
            }
        }
    
        //等待获取锁
        @Override
        protected void waitLock() {
            //如果已经有线程创建了临时节点,那么其他线程只能等待,不能再创建该临时节点
            //那么就监听你这个临时节点,如果该节点被删除了,那我等待结束,就又可以创建临时节点
    
            //订阅数据改变,就是监听参数中指定的那个节点
            IZkDataListener listener = new IZkDataListener() {
                @Override
                public void handleDataChange(String s, Object o) throws Exception {
    
                }
    
                @Override
                public void handleDataDeleted(String s) throws Exception {
                    if (countDownLatch != null) {
                        //计数减1
                        countDownLatch.countDown();
                    }
                }
            };
            //1、监听
            zkClient.subscribeDataChanges(lock, listener);
    
    //        2、判断那个锁的节点是否存在
            if (zkClient.exists(lock)) {
                countDownLatch = new CountDownLatch(1);
                try {
                    //等待
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    //        3、订阅要取消一下
            zkClient.unsubscribeDataChanges(lock, listener);
        }
    }
    

    具体使用

       		//业务代码加zookeeper分布式锁
            ZookeeperDistributedLock lock = new ZookeeperDistributedLock("/lock_nodeName");
            try {
                lock.lock();
               //加锁业务代码
                ……
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
  • 相关阅读:
    windows下忘记mysql超级管理员rootpassword的解决的方法
    LeetCode226 InvertBinaryTree Java题解
    PHP利用GD库绘图和生成验证码图片
    自己动手开发IOC容器
    智能提示(一) Solr (suggest)
    Linux系统字符集乱码问题
    Linux
    [Material Design] 教你做一个Material风格、动画的button(MaterialButton)
    codeforces#FF(div2) D DZY Loves Modification
    鼠标滚轮实现图片的缩放-------Day79
  • 原文地址:https://www.cnblogs.com/yhongyin/p/12046890.html
Copyright © 2020-2023  润新知