• Zookeeper 分布式锁


    http://blog.csdn.net/java2000_wl/article/details/8694270


    获取锁实现思路:

    1.     首先创建一个作为锁目录(znode),通常用它来描述锁定的实体,称为:/lock_node

    2.     希望获得锁的客户端在锁目录下创建znode,作为锁/lock_node的子节点,并且节点类型为有序临时节点(EPHEMERAL_SEQUENTIAL);

            例如:有两个客户端创建znode,分别为/lock_node/lock-1和/lock_node/lock-2

    3.     当前客户端调用getChildren(/lock_node)得到锁目录所有子节点,不设置watch,接着获取小于自己(步骤2创建)的兄弟节点

    4.     步骤3中获取小于自己的节点不存在 && 最小节点与步骤2中创建的相同,说明当前客户端顺序号最小,获得锁,结束。

    5.     客户端监视(watch)相对自己次小的有序临时节点状态

    6.     如果监视的次小节点状态发生变化,则跳转到步骤3,继续后续操作,直到退出锁竞争。

     

    1. public synchronized boolean lock() throws KeeperException, InterruptedException {  
    2.        if (isClosed()) {  
    3.            return false;  
    4.        }  
    5.        // 如果锁目录不存在, 创建锁目录   节点类型为永久类型  
    6.        ensurePathExists(dir);  
    7.   
    8.        // 创建锁节点,节点类型EPHEMERAL_SEQUENTIAL   
    9.        // 如果不存在小于自己的节点   并且最小节点 与当前创建的节点相同  获得锁  
    10.        // 未获得成功,对当前次小节点设置watch  
    11.        return (Boolean) retryOperation(zop);  
    12.    }  

     

    创建锁目录

    1. protected void ensurePathExists(String path) {  
    2.     ensureExists(path, null, acl, CreateMode.PERSISTENT);  
    3. }  
    1. protected void ensureExists(final String path, final byte[] data,  
    2.         final List<ACL> acl, final CreateMode flags) {  
    3.     try {  
    4.         retryOperation(new ZooKeeperOperation() {  
    5.             public boolean execute() throws KeeperException, InterruptedException {  
    6.                 // 创建锁目录  
    7.                 Stat stat = zookeeper.exists(path, false);  
    8.                 // 节点如果存在  直接返回  
    9.                 if (stat != null) {  
    10.                     return true;  
    11.                 }  
    12.                 // 创建节点  
    13.                 // data为null  
    14.                 // flags为持久化节点  
    15.                 zookeeper.create(path, data, acl, flags);  
    16.                 return true;  
    17.             }  
    18.         });  
    19.     } catch (KeeperException e) {  
    20.         LOG.warn("Caught: " + e, e);  
    21.     } catch (InterruptedException e) {  
    22.         LOG.warn("Caught: " + e, e);  
    23.     }  
    24. }  

    创建锁节点,获得锁目录下的所有节点, 如果为最小节点 获得锁成功

     

    1.     /** 
    2.      * the command that is run and retried for actually  
    3.      * obtaining the lock 
    4.      * @return if the command was successful or not 
    5.      */  
    6.     public boolean execute() throws KeeperException, InterruptedException {  
    7.         do {  
    8.             if (id == null) {  
    9.                 long sessionId = zookeeper.getSessionId();  
    10.                 String prefix = "x-" + sessionId + "-";  
    11.                 // lets try look up the current ID if we failed   
    12.                 // in the middle of creating the znode  
    13.                 findPrefixInChildren(prefix, zookeeper, dir);  
    14.                 idName = new ZNodeName(id);  
    15.             }  
    16.             if (id != null) {  
    17.                 List<String> names = zookeeper.getChildren(dir, false);  
    18.                 if (names.isEmpty()) {  
    19.                     LOG.warn("No children in: " + dir + " when we've just " +  
    20.                     "created one! Lets recreate it...");  
    21.                     // lets force the recreation of the id  
    22.                     id = null;  
    23.                 } else {  
    24.                     // lets sort them explicitly (though they do seem to come back in order ususally :)  
    25.                     SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>();  
    26.                     for (String name : names) {  
    27.                         sortedNames.add(new ZNodeName(dir + "/" + name));  
    28.                     }  
    29.                     // 获得最小节点  
    30.                     ownerId = sortedNames.first().getName();  
    31.                     // lock_1, lock_2, lock_3  传入参数lock_2  返回lock_1  
    32.                     SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName);  
    33.                     if (!lessThanMe.isEmpty()) {  
    34.                         ZNodeName lastChildName = lessThanMe.last();  
    35.                         lastChildId = lastChildName.getName();  
    36.                         if (LOG.isDebugEnabled()) {  
    37.                             LOG.debug("watching less than me node: " + lastChildId);  
    38.                         }  
    39.                         // 次小节点设置watch   
    40.                         Stat stat = zookeeper.exists(lastChildId, new LockWatcher());  
    41.                         if (stat != null) {  
    42.                             return Boolean.FALSE;  
    43.                         } else {  
    44.                             LOG.warn("Could not find the" +  
    45.                                     " stats for less than me: " + lastChildName.getName());  
    46.                         }  
    47.                     } else {  
    48.                         // 锁目录下的最小节点  与当前客户端创建相同  
    49.                         if (isOwner()) {  
    50.                             if (callback != null) {  
    51.                                 callback.lockAcquired();  
    52.                             }  
    53.                             // 获得锁  
    54.                             return Boolean.TRUE;  
    55.                         }  
    56.                     }  
    57.                 }  
    58.             }  
    59.         }  
    60.         while (id == null);  
    61.         return Boolean.FALSE;  
    62.     }  
    63. };  

    1. private void findPrefixInChildren(String prefix, ZooKeeper zookeeper, String dir)   
    2.             throws KeeperException, InterruptedException {  
    3.             // 获取锁目录下的所有子节点  
    4.             List<String> names = zookeeper.getChildren(dir, false);  
    5.             for (String name : names) {  
    6.                 //x-sessionId-  
    7.                 if (name.startsWith(prefix)) {  
    8.                     id = name;  
    9.                     if (LOG.isDebugEnabled()) {  
    10.                         LOG.debug("Found id created last time: " + id);  
    11.                     }  
    12.                     break;  
    13.                 }  
    14.             }  
    15.             // 当前锁目录下   没有与当前会话对应的子节点    创建子节点  节点类型为临时顺序节点  
    16.             if (id == null) {  
    17.                 // dir/x-sessionId-i  
    18.                 id = zookeeper.create(dir + "/" + prefix, data,   
    19.                         getAcl(), EPHEMERAL_SEQUENTIAL);  
    20.   
    21.                 if (LOG.isDebugEnabled()) {  
    22.                     LOG.debug("Created id: " + id);  
    23.                 }  
    24.             }  

     

    释放锁:

    释放锁非常简单,删除步骤1中创建的有序临时节点。另外,如果客户端进程死亡或连接失效,对应的节点也会被删除。

     

    1. public synchronized void unlock() throws RuntimeException {  
    2.          
    3.        if (!isClosed() && id != null) {  
    4.            // we don't need to retry this operation in the case of failure  
    5.            // as ZK will remove ephemeral files and we don't wanna hang  
    6.            // this process when closing if we cannot reconnect to ZK  
    7.            try {  
    8.                  
    9.                ZooKeeperOperation zopdel = new ZooKeeperOperation() {  
    10.                    public boolean execute() throws KeeperException,  
    11.                        InterruptedException {  
    12.                     // 删除节点  忽略版本  
    13.                        zookeeper.delete(id, -1);     
    14.                        return Boolean.TRUE;  
    15.                    }  
    16.                };  
    17.                zopdel.execute();  
    18.            } catch (InterruptedException e) {  
    19.                LOG.warn("Caught: " + e, e);  
    20.                //set that we have been interrupted.  
    21.               Thread.currentThread().interrupt();  
    22.            } catch (KeeperException.NoNodeException e) {  
    23.                // do nothing  
    24.            } catch (KeeperException e) {  
    25.                LOG.warn("Caught: " + e, e);  
    26.                throw (RuntimeException) new RuntimeException(e.getMessage()).  
    27.                    initCause(e);  
    28.            }  
    29.            finally {  
    30.                if (callback != null) {  
    31.                    callback.lockReleased();  
    32.                }  
    33.                id = null;  
    34.            }  
    35.        }  
    36.    }  


    背景

     继续上一篇文章:http://agapple.iteye.com/blog/1183972 ,项目中需要对分布式任务进行调度,那对应的分布式lock实现在所难免。

     

     这一周,在基于BooleanMutex的基础上,实现了zookeeper的分布式锁,用于控制多进程+多线程的lock控制

     

    算法

    可以预先看一下zookeeper的官方文档: 

     

    lock操作过程:
    • 首先为一个lock场景,在zookeeper中指定对应的一个根节点,用于记录资源竞争的内容
    • 每个lock创建后,会lazy在zookeeper中创建一个node节点,表明对应的资源竞争标识。 (小技巧:node节点为EPHEMERAL_SEQUENTIAL,自增长的临时节点)
    • 进行lock操作时,获取对应lock根节点下的所有字节点,也即处于竞争中的资源标识
    • 按照Fair竞争的原则,按照对应的自增内容做排序,取出编号最小的一个节点做为lock的owner,判断自己的节点id是否就为owner id,如果是则返回,lock成功。
    • 如果自己非owner id,按照排序的结果找到序号比自己前一位的id,关注它锁释放的操作(也就是exist watcher),形成一个链式的触发过程。
    unlock操作过程:
    • 将自己id对应的节点删除即可,对应的下一个排队的节点就可以收到Watcher事件,从而被唤醒得到锁后退出

    其中的几个关键点:
    1. node节点选择为EPHEMERAL_SEQUENTIAL很重要。
      * 自增长的特性,可以方便构建一个基于Fair特性的锁,前一个节点唤醒后一个节点,形成一个链式的触发过程。可以有效的避免"惊群效应"(一个锁释放,所有等待的线程都被唤醒),有针对性的唤醒,提升性能。
      * 选择一个EPHEMERAL临时节点的特性。因为和zookeeper交互是一个网络操作,不可控因素过多,比如网络断了,上一个节点释放锁的操作会失败。临时节点是和对应的session挂接的,session一旦超时或者异常退出其节点就会消失,类似于ReentrantLock中等待队列Thread的被中断处理。
    2. 获取lock操作是一个阻塞的操作,而对应的Watcher是一个异步事件,所以需要使用信号进行通知,正好使用上一篇文章中提到的BooleanMutex,可以比较方便的解决锁重入的问题。(锁重入可以理解为多次读操作,锁释放为写抢占操作)

    注意:
    • 使用EPHEMERAL会引出一个风险:在非正常情况下,网络延迟比较大会出现session timeout,zookeeper就会认为该client已关闭,从而销毁其id标示,竞争资源的下一个id就可以获取锁。这时可能会有两个process同时拿到锁在跑任务,所以设置好session timeout很重要。
    • 同样使用PERSISTENT同样会存在一个死锁的风险,进程异常退出后,对应的竞争资源id一直没有删除,下一个id一直无法获取到锁对象。
    没有两全其美的做法,两者取其一,选择自己一个能接受的即可

     

    代码

    Java代码  收藏代码
    1. public class DistributedLock {  
    2.   
    3.     private static final byte[]  data      = { 0x120x34 };  
    4.     private ZooKeeperx           zookeeper = ZooKeeperClient.getInstance();  
    5.     private final String         root;                                     //根节点路径  
    6.     private String               id;  
    7.     private LockNode             idName;  
    8.     private String               ownerId;  
    9.     private String               lastChildId;  
    10.     private Throwable            other     = null;  
    11.     private KeeperException      exception = null;  
    12.     private InterruptedException interrupt = null;  
    13.   
    14.     public DistributedLock(String root) {  
    15.         this.root = root;  
    16.         ensureExists(root);  
    17.     }  
    18.   
    19.     /** 
    20.      * 尝试获取锁操作,阻塞式可被中断 
    21.      */  
    22.     public void lock() throws InterruptedException, KeeperException {  
    23.         // 可能初始化的时候就失败了  
    24.         if (exception != null) {  
    25.             throw exception;  
    26.         }  
    27.   
    28.         if (interrupt != null) {  
    29.             throw interrupt;  
    30.         }  
    31.   
    32.         if (other != null) {  
    33.             throw new NestableRuntimeException(other);  
    34.         }  
    35.   
    36.         if (isOwner()) {//锁重入  
    37.             return;  
    38.         }  
    39.   
    40.         BooleanMutex mutex = new BooleanMutex();  
    41.         acquireLock(mutex);  
    42.         // 避免zookeeper重启后导致watcher丢失,会出现死锁使用了超时进行重试  
    43.         try {  
    44.             mutex.get(DEFAULT_TIMEOUT_PERIOD, TimeUnit.MICROSECONDS);// 阻塞等待值为true  
    45.             // mutex.get();  
    46.         } catch (TimeoutException e) {  
    47.             if (!mutex.state()) {  
    48.                 lock();  
    49.             }  
    50.         }  
    51.   
    52.         if (exception != null) {  
    53.             throw exception;  
    54.         }  
    55.   
    56.         if (interrupt != null) {  
    57.             throw interrupt;  
    58.         }  
    59.   
    60.         if (other != null) {  
    61.             throw new NestableRuntimeException(other);  
    62.         }  
    63.     }  
    64.   
    65.     /** 
    66.      * 尝试获取锁对象, 不会阻塞 
    67.      *  
    68.      * @throws InterruptedException 
    69.      * @throws KeeperException 
    70.      */  
    71.     public boolean tryLock() throws KeeperException {  
    72.         // 可能初始化的时候就失败了  
    73.         if (exception != null) {  
    74.             throw exception;  
    75.         }  
    76.   
    77.         if (isOwner()) {//锁重入  
    78.             return true;  
    79.         }  
    80.   
    81.         acquireLock(null);  
    82.   
    83.         if (exception != null) {  
    84.             throw exception;  
    85.         }  
    86.   
    87.         if (interrupt != null) {  
    88.             Thread.currentThread().interrupt();  
    89.         }  
    90.   
    91.         if (other != null) {  
    92.             throw new NestableRuntimeException(other);  
    93.         }  
    94.   
    95.         return isOwner();  
    96.     }  
    97.   
    98.     /** 
    99.      * 释放锁对象 
    100.      */  
    101.     public void unlock() throws KeeperException {  
    102.         if (id != null) {  
    103.             try {  
    104.                 zookeeper.delete(root + "/" + id, -1);  
    105.             } catch (InterruptedException e) {  
    106.                 Thread.currentThread().interrupt();  
    107.             } catch (KeeperException.NoNodeException e) {  
    108.                 // do nothing  
    109.             } finally {  
    110.                 id = null;  
    111.             }  
    112.         } else {  
    113.             //do nothing  
    114.         }  
    115.     }  
    116.   
    117.     private void ensureExists(final String path) {  
    118.         try {  
    119.             Stat stat = zookeeper.exists(path, false);  
    120.             if (stat != null) {  
    121.                 return;  
    122.             }  
    123.   
    124.             zookeeper.create(path, data, CreateMode.PERSISTENT);  
    125.         } catch (KeeperException e) {  
    126.             exception = e;  
    127.         } catch (InterruptedException e) {  
    128.             Thread.currentThread().interrupt();  
    129.             interrupt = e;  
    130.         }  
    131.     }  
    132.   
    133.     /** 
    134.      * 返回锁对象对应的path 
    135.      */  
    136.     public String getRoot() {  
    137.         return root;  
    138.     }  
    139.   
    140.     /** 
    141.      * 判断当前是不是锁的owner 
    142.      */  
    143.     public boolean isOwner() {  
    144.         return id != null && ownerId != null && id.equals(ownerId);  
    145.     }  
    146.   
    147.     /** 
    148.      * 返回当前的节点id 
    149.      */  
    150.     public String getId() {  
    151.         return this.id;  
    152.     }  
    153.   
    154.     // ===================== helper method =============================  
    155.   
    156.     /** 
    157.      * 执行lock操作,允许传递watch变量控制是否需要阻塞lock操作 
    158.      */  
    159.     private Boolean acquireLock(final BooleanMutex mutex) {  
    160.         try {  
    161.             do {  
    162.                 if (id == null) {//构建当前lock的唯一标识  
    163.                     long sessionId = zookeeper.getDelegate().getSessionId();  
    164.                     String prefix = "x-" + sessionId + "-";  
    165.                     //如果第一次,则创建一个节点  
    166.                     String path = zookeeper.create(root + "/" + prefix, data,  
    167.                             CreateMode.EPHEMERAL_SEQUENTIAL);  
    168.                     int index = path.lastIndexOf("/");  
    169.                     id = StringUtils.substring(path, index + 1);  
    170.                     idName = new LockNode(id);  
    171.                 }  
    172.   
    173.                 if (id != null) {  
    174.                     List<String> names = zookeeper.getChildren(root, false);  
    175.                     if (names.isEmpty()) {  
    176.                         id = null;//异常情况,重新创建一个  
    177.                     } else {  
    178.                         //对节点进行排序  
    179.                         SortedSet<LockNode> sortedNames = new TreeSet<LockNode>();  
    180.                         for (String name : names) {  
    181.                             sortedNames.add(new LockNode(name));  
    182.                         }  
    183.   
    184.                         if (sortedNames.contains(idName) == false) {  
    185.                             id = null;//清空为null,重新创建一个  
    186.                             continue;  
    187.                         }  
    188.   
    189.                         //将第一个节点做为ownerId  
    190.                         ownerId = sortedNames.first().getName();  
    191.                         if (mutex != null && isOwner()) {  
    192.                             mutex.set(true);//直接更新状态,返回  
    193.                             return true;  
    194.                         } else if (mutex == null) {  
    195.                             return isOwner();  
    196.                         }  
    197.   
    198.                         SortedSet<LockNode> lessThanMe = sortedNames.headSet(idName);  
    199.                         if (!lessThanMe.isEmpty()) {  
    200.                             //关注一下排队在自己之前的最近的一个节点  
    201.                             LockNode lastChildName = lessThanMe.last();  
    202.                             lastChildId = lastChildName.getName();  
    203.                             //异步watcher处理  
    204.                             zookeeper.exists(root + "/" + lastChildId, new AsyncWatcher() {  
    205.   
    206.                                 public void asyncProcess(WatchedEvent event) {  
    207.                                     acquireLock(mutex);  
    208.                                 }  
    209.   
    210.                             });  
    211.   
    212.                             if (stat == null) {  
    213.                                 acquireLock(mutex);// 如果节点不存在,需要自己重新触发一下,watcher不会被挂上去  
    214.                             }  
    215.                         } else {  
    216.                             if (isOwner()) {  
    217.                                 mutex.set(true);  
    218.                             } else {  
    219.                                 id = null;// 可能自己的节点已超时挂了,所以id和ownerId不相同  
    220.                             }  
    221.                         }  
    222.                     }  
    223.                 }  
    224.             } while (id == null);  
    225.         } catch (KeeperException e) {  
    226.             exception = e;  
    227.             if (mutex != null) {  
    228.                 mutex.set(true);  
    229.             }  
    230.         } catch (InterruptedException e) {  
    231.             interrupt = e;  
    232.             if (mutex != null) {  
    233.                 mutex.set(true);  
    234.             }  
    235.         } catch (Throwable e) {  
    236.             other = e;  
    237.             if (mutex != null) {  
    238.                 mutex.set(true);  
    239.             }  
    240.         }  
    241.   
    242.         if (isOwner() && mutex != null) {  
    243.             mutex.set(true);  
    244.         }  
    245.         return Boolean.FALSE;  
    246.     }  
    247. }  

    相关说明:


     

     

    测试代码:

     

    Java代码  收藏代码
    1. @Test  
    2.     public void test_lock() {  
    3.         ExecutorService exeucotr = Executors.newCachedThreadPool();  
    4.         final int count = 50;  
    5.         final CountDownLatch latch = new CountDownLatch(count);  
    6.         final DistributedLock[] nodes = new DistributedLock[count];  
    7.         for (int i = 0; i < count; i++) {  
    8.             final DistributedLock node = new DistributedLock(dir);  
    9.             nodes[i] = node;  
    10.             exeucotr.submit(new Runnable() {  
    11.   
    12.                 public void run() {  
    13.                     try {  
    14.                         Thread.sleep(1000);  
    15.                         node.lock(); //获取锁  
    16.                         Thread.sleep(100 + RandomUtils.nextInt(100));  
    17.   
    18.                         System.out.println("id: " + node.getId() + " is leader: " + node.isOwner());  
    19.                     } catch (InterruptedException e) {  
    20.                         want.fail();  
    21.                     } catch (KeeperException e) {  
    22.                         want.fail();  
    23.                     } finally {  
    24.                         latch.countDown();  
    25.                         try {  
    26.                             node.unlock();  
    27.                         } catch (KeeperException e) {  
    28.                             want.fail();  
    29.                         }  
    30.                     }  
    31.   
    32.                 }  
    33.             });  
    34.         }  
    35.   
    36.         try {  
    37.             latch.await();  
    38.         } catch (InterruptedException e) {  
    39.             want.fail();  
    40.         }  
    41.   
    42.         exeucotr.shutdown();  
    43.     }  

     

    升级版

     实现了一个分布式lock后,可以解决多进程之间的同步问题,但设计多线程+多进程的lock控制需求,单jvm中每个线程都和zookeeper进行网络交互成本就有点高了,所以基于DistributedLock,实现了一个分布式二层锁。

     

    大致原理就是ReentrantLock 和 DistributedLock的一个结合。

     

     

    •  单jvm的多线程竞争时,首先需要先拿到第一层的ReentrantLock的锁
    • 拿到锁之后这个线程再去和其他JVM的线程竞争锁,最后拿到之后锁之后就开始处理任务。
    锁的释放过程是一个反方向的操作,先释放DistributedLock,再释放ReentrantLock。 可以思考一下,如果先释放ReentrantLock,假如这个JVM ReentrantLock竞争度比较高,一直其他JVM的锁竞争容易被饿死。

    代码:
    Java代码  收藏代码
    1. public class DistributedReentrantLock extends DistributedLock {  
    2.   
    3.     private static final String ID_FORMAT     = "Thread[{0}] Distributed[{1}]";  
    4.     private ReentrantLock       reentrantLock = new ReentrantLock();  
    5.   
    6.     public DistributedReentrantLock(String root) {  
    7.         super(root);  
    8.     }  
    9.   
    10.     public void lock() throws InterruptedException, KeeperException {  
    11.         reentrantLock.lock();//多线程竞争时,先拿到第一层锁  
    12.         super.lock();  
    13.     }  
    14.   
    15.     public boolean tryLock() throws KeeperException {  
    16.         //多线程竞争时,先拿到第一层锁  
    17.         return reentrantLock.tryLock() && super.tryLock();  
    18.     }  
    19.   
    20.     public void unlock() throws KeeperException {  
    21.         super.unlock();  
    22.         reentrantLock.unlock();//多线程竞争时,释放最外层锁  
    23.     }  
    24.   
    25.     @Override  
    26.     public String getId() {  
    27.         return MessageFormat.format(ID_FORMAT, Thread.currentThread().getId(), super.getId());  
    28.     }  
    29.   
    30.     @Override  
    31.     public boolean isOwner() {  
    32.         return reentrantLock.isHeldByCurrentThread() && super.isOwner();  
    33.     }  
    34.   
    35. }  
     
    测试代码:
    Java代码  收藏代码
    1. @Test  
    2.     public void test_lock() {  
    3.         ExecutorService exeucotr = Executors.newCachedThreadPool();  
    4.         final int count = 50;  
    5.         final CountDownLatch latch = new CountDownLatch(count);  
    6.   
    7.         final DistributedReentrantLock lock = new DistributedReentrantLock(dir); //单个锁  
    8.         for (int i = 0; i < count; i++) {  
    9.             exeucotr.submit(new Runnable() {  
    10.   
    11.                 public void run() {  
    12.                     try {  
    13.                         Thread.sleep(1000);  
    14.                         lock.lock();  
    15.                         Thread.sleep(100 + RandomUtils.nextInt(100));  
    16.   
    17.                         System.out.println("id: " + lock.getId() + " is leader: " + lock.isOwner());  
    18.                     } catch (InterruptedException e) {  
    19.                         want.fail();  
    20.                     } catch (KeeperException e) {  
    21.                         want.fail();  
    22.                     } finally {  
    23.                         latch.countDown();  
    24.                         try {  
    25.                             lock.unlock();  
    26.                         } catch (KeeperException e) {  
    27.                             want.fail();  
    28.                         }  
    29.                     }  
    30.   
    31.                 }  
    32.             });  
    33.         }  
    34.   
    35.         try {  
    36.             latch.await();  
    37.         } catch (InterruptedException e) {  
    38.             want.fail();  
    39.         }  
    40.   
    41.         exeucotr.shutdown();  
    42.     }  

    最后

    其实再可以发散一下,实现一个分布式的read/write lock,也差不多就是这个理了。项目结束后,有时间可以写一下

     

    大致思路:

     

    1. 竞争资源标示:  read_自增id , write_自增id
    2. 首先按照自增id进行排序,如果队列的前边都是read标识,对应的所有read都获得锁。如果队列的前边是write标识,第一个write节点获取锁
    3. watcher监听: read监听距离自己最近的一个write节点的exist,write监听距离自己最近的一个节点(read或者write节点)

     

  • 相关阅读:
    JDK中Unsafe类详解
    JAVA并发理论与实践
    关于FastJSON
    指数退避算法
    MySQL多表关联查询效率高点还是多次单表查询效率高,为什么?
    App开放接口api安全性—Token签名sign的设计与实现
    使用Jmeter进行http接口性能测试
    短信验证登录实现流程
    使用 Postman 取得 Token 打另一隻 API
    SpringMVC拦截器HandlerInterceptor使用
  • 原文地址:https://www.cnblogs.com/leeeee/p/7276164.html
Copyright © 2020-2023  润新知