ZooKeeper distributed lock to achieve

 

Distributed Lock There are three general ways:

1. Database optimistic locking;

2. Redis-based distributed lock;

3. Based on ZooKeeper distributed lock.

This blog will introduce a third way, based on the realization Zookeeper distributed lock. Although the Internet has introduced a variety of Zookeeper distributed lock implemented blog, but they realize they have a variety of problems, in order to avoid fraught, this blog will detail how to implement the Zookeeper distributed lock properly.

  Now use a simulation to achieve Zookeeper distributed lock, assuming that there are A, B, C three clients to access resources, call zookeeper get the lock. Three create a client / lock node under / locks node zookeeper, because the node is the uniqueness of the properties, only one person will be successfully created, and the remaining two creation fails, it will change into the monitor / locks node, if / locks erupted node / lock node changes, the other two can pick locks, whether this is good? Like this can lead to shock group effect. It is a trigger so that it will trigger a lot in a short time watcher of events, but only one client can get a lock. So this approach is not recommended.

  There is a better approach is to use the ordered node zookeeper's characteristics, the basic idea:

1, create a temporary order of the nodes in the locker node in a distributed lock acquisition time, delete the temporary node when the lock is released.

2, the client calls createNode method to create a temporary order of nodes in the locks, and then call getChildren ( "locks") to acquire all the child nodes locks below, note this time without setting any Watcher.

3, after the clients obtain all the child nodes path, if we find the minimum number of child nodes that you have created, it considers the client to get a lock.

4, if the discovery node to create their own locks is not all child nodes of the smallest, indicating that he still did not get the lock, then the client needs to find the node is smaller than its own, then it calls the exist () method, while its register event listeners.

5, then, let this node is concerned about the deletion, the client's Watcher will receive appropriate notice, this time again to determine whether the node that you create are locks child nodes smallest number, if it is acquired to lock, if it is not repeat the above steps to continue to acquire smaller than a node and its registered listeners.

 The following look at my code to achieve:

public  class DistributedLock the implements Lock, Watcher { 
 
    Private the ZooKeeper ZK = null ;
     Private String ROOT_LOCK = "/ Locks"; // definition of root 
    Private String WAIT_LOCK; // a lock wait before 
    Private String CURRENT_LOCK; // indicates the current lock
     // as blocking 
    Private a CountDownLatch CountDownLatch; //
  
 
    public DistributedLock () { 
 
        the try { 
            ZK = new new the ZooKeeper ( "192.168.254.135:2181" ,
                     4000, the this);
             // determines whether there is a root node 
            Stat STAT = zk.exists (ROOT_LOCK, to false );
             IF (STAT == null ) { // If create absent 
                zk.create (ROOT_LOCK, "0" .getBytes (), 
                        ZooDefs .Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 
            } 
        } the catch (IOException E) { 
            e.printStackTrace (); 
        } the catch (InterruptedException E) { 
            e.printStackTrace (); 
        } the catch (KeeperException E) { 
            e.printStackTrace (); 
        }
 
    } 
 
    / ** 
     * try to acquire locks 
     * / 
    @Override 
    public  Boolean tryLock () { 
 
        the try {
             // Create a temporary ordered node 
            CURRENT_LOCK = zk.create (ROOT_LOCK + "/", "0" .getBytes (), 
                    ZooDefs.Ids. OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); 
            System.out.println (Thread.currentThread () getName (). + "->" + 
                    CURRENT_LOCK + ", attempt to lock contention" ); 
            List <String> Childrens = zk.getChildren (ROOT_LOCK, to false ); // Get all the child nodes below the root node 
            the SortedSet <String> = SortedSet new newTreeSet (); // define a set of sort 
            for (String Children: Childrens) { // Sort 
                sortedSet.add (ROOT_LOCK + "/" + Children); 
            } 
            String firstNode = sortedSet.first (); // get all current sub the smallest node node
             // remove nodes than I created smaller nodes, if not for the null 
            SortedSet <String> lessThenMe = ((TreeSet <String> ) SortedSet) .headSet (CURRENT_LOCK);
             IF (CURRENT_LOCK.equals (firstNode )) { // by the current node and child node of the smallest node comparison, if they are equal, the lock is obtained indicates successful 
                return  to true ; 
            } 
            IF (! lessThenMe.isEmpty ()) {
                WAIT_LOCKlessThenMe.last = (); // get the current node is smaller than the last node is provided to WAIT_LOCK 
            } 
        } the catch (KeeperException E) { 
            e.printStackTrace (); 
        } the catch (InterruptedException E) { 
            e.printStackTrace (); 
        } 
        return  to false ; 
    } 
 
 
    @Override 
    public  void lock () {
         IF ( the this .tryLock ()) { // If successful lock is obtained 
            . System.out.println (Thread.currentThread () getName ( ) + "->" + CURRENT_LOCK + "-> to obtain a lock successfully" );
             return ; 
        }
         The try { 
            waitForLock (WAIT_LOCK); // do not get the lock, wait for a lock to continue 
        } the catch (KeeperException E) { 
            e.printStackTrace (); 
        } the catch (InterruptedException E) { 
            e.printStackTrace (); 
        } 
    } 
 
    Private  Boolean waitForLock (String prev) throws KeeperException, InterruptedException {
         // listening on a node of the current node registered event, here need to be addressed in the default watch events inside
         // here is the process inside the callback Please watch events we mentioned before trigger execution of final See most downlink codes 
        Stat STAT = zk.exists (PREV, to true );
        IF  (STAT =!null ) { 
            . System.out.println (Thread.currentThread () getName () + "-> Lock Wait" + ROOT_LOCK + "/" + prev + " release" ); 
            CountDownLatch = new new a CountDownLatch (. 1 ); 
            CountDownLatch.await ( ); // enters a wait, there needs
             // later TODO watcher trigger, also we need to determine the current node is not a minimum wait again 
            System.out.println (Thread.currentThread () getName () + "-> get the lock success. " ); 
        } 
        return  to true ;
    }
 
    @Override
    public void lockInterruptibly() throws InterruptedException {
 
    }
 
    @Override
    public  Boolean tryLock ( Long Time, TimeUnit Unit) throws InterruptedException {
         return  to false ; 
    } 
 
    @Override 
    public  void UNLOCK () { 
        System.out.println (. Thread.currentThread () getName () + "-> release locks" + CURRENT_LOCK) ;
         the try {
             // -1 represents the first node deleted anyway say 
            zk.delete (CURRENT_LOCK, -1 ); 
            CURRENT_LOCK = null ; 
            zk.close (); 
        } the catch (InterruptedException E) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
 
    @Override
    public Condition newCondition() {
        return null;
    }
 
    @Override
    public void process(WatchedEvent event) {
        // 事件回调 countDownLatch.countDown();
        if(this.countDownLatch!=null){
            this.countDownLatch.countDown();
        }
    }
}

Code implements Lock, Watcher two interfaces. The main lock is used inside trylock method, attempt to acquire the lock. Then there watcher inside the callback processing method

Test code

public static void main( String[] args ) throws IOException {
       CountDownLatch countDownLatch=new CountDownLatch(10);
       for(int i=0;i<10;i++){
           new Thread(()->{
               try {
                   countDownLatch.await();
                   DistributedLock distributedLock=new DistributedLock();
                   distributedLock.lock(); //获得锁
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           },"Thread-"+i).start();
           countDownLatch.countDown();
       }
       System.in.read();
   }

operation result:

. 8-the Thread -> / Locks / 0000000040 , lock contention attempt 
the Thread -5 -> / Locks / 0,000,000,044 , lock contention attempt 
the Thread -9 -> / Locks / 0,000,000,041 , lock contention attempt 
the Thread -3 -> / Locks / 0,000,000,042 , try competition lock 
the Thread -7 -> / locks / 0,000,000,046 , lock contention attempt 
the Thread -1 -> / locks / 0,000,000,043 , lock contention attempt 
the Thread -0 -> / locks / 0,000,000,047 , lock contention attempt 
the Thread -4 -> / locks / 0,000,000,045 , lock contention attempt 
the Thread -2 -> / locks / 0000000049 , lock contention attempt 
the Thread -6 -> / locks / 0,000,000,048 , lock contention attempt 
the Thread -8 -> / locks / 0000000040-> obtained successfully lock 
the Thread -9-> wait lock / locks //locks / 0000000040 release 
Thread-5-> waiting for the lock / Locks // Locks / 0,000,000,043 release 
Thread-0-> waiting for the lock / Locks // Locks / 0,000,000,046 release 
Thread-1-> waiting for the lock / Locks // Locks / 0,000,000,042 release 
Thread -2-> waiting for the lock / locks // locks / 0,000,000,048 release 
Thread-7-> waiting for the lock / locks // locks / 0,000,000,045 release 
Thread-6-> waiting for the lock / locks // locks / 0,000,000,047 release 
Thread-3-> wait lock / locks // locks / 0000000041 release 
Thread-4-> waiting for the lock / locks // locks / release 0,000,000,044

 

Guess you like

Origin www.cnblogs.com/luxianyu-s/p/11328615.html