static String waitInLine ( ZooKeeper zookeeper , String lockNode , String placeInLine ) throws KeeperException , InterruptedException { // Get the list of nodes in the queue, and find out what our position is. List < String > children = zookeeper . getChildren ( lockNode , false ) ; // The list returned is unsorted. Collections . sort ( children ) ; if ( children . size ( ) == 0 ) { // Only possible if some other process cancelled our ticket. logger . warn ( "getChildren() returned empty list, but we created a ticket." ) ; return acquireLock ( zookeeper , lockNode ) ; } boolean lockingTicketExists = children . get ( 0 ) . equals ( LOCKING_TICKET ) ; if ( lockingTicketExists ) { children . remove ( 0 ) ; } // Where are we in the queue? int positionInQueue = - 1 ; int i = 0 ; for ( String child : children ) { if ( child . equals ( placeInLine ) ) { positionInQueue = i ; break ; } i ++ ; } if ( positionInQueue < 0 ) { // Theoretically not possible. throw new RuntimeException ( "Created node (" + placeInLine + ") not found in getChildren()." ) ; } String placeBeforeUs ; if ( positionInQueue == 0 ) { // Lowest number in the queue, go for the lock. if ( grabTicket ( zookeeper , lockNode , LOCKING_TICKET ) ) { releaseTicket ( zookeeper , lockNode , placeInLine ) ; return LOCKING_TICKET ; } else { placeBeforeUs = LOCKING_TICKET ; } } else { // We are not in front of the queue, so we keep an eye on the znode right in front of us. When it is // deleted, that means it has reached the front of the queue, acquired the lock, did its business, // and released the lock. placeBeforeUs = children . get ( positionInQueue - 1 ) ; } final CountDownLatch latch = new CountDownLatch ( 1 ) ; Stat stat = zookeeper . exists ( lockNode + "/" + placeBeforeUs , event -> { // If *anything* changes, reevaluate our position in the queue. latch . countDown ( ) ; } ) ; // If stat is null, the znode in front of use got deleted during our inspection of the queue. If that happens, // simply reevaluate our position in the queue again. If there *is* a znode in front of us, // watch it for changes: if ( stat != null ) { logger . debug ( "Watching place in queue before us ({})" , placeBeforeUs ) ; latch . await ( ) ; } return waitInLine ( zookeeper , lockNode , placeInLine ) ; }
Wait in the queue until the znode in front of us changes .