The Ephemeral_sequential type node and watcher mechanism of zookeeper are used to realize the distributed lock simply.
Main ideas:
1, open 10 threads, under the Dislocks node respectively to create a ephemeral_sequential node named sub;
2, get the Dislocks node under all the child nodes, sorting, if their own node number is minimal, then get the lock;
3, otherwise watch row in front of their nodes, listening to its deletion, into the 2nd step (re-detection of the sorting is to prevent the connection failure of the listening node, resulting in the deletion of the node);
4, delete its own sub nodes, release the connection;
Here's the Zookeeper 4 node types:
public enum Createmode {/** * Persistent node: After the node is created, it will always exist and will not be deleted because the client session failed; */persistent
(0, False, false),/** * Persistent order node: the basic characteristics are consistent with the persistent node, in the process of creating a node, Zookeeper automatically appends a monotonically growing number suffix to the new node name after its name; /Persistent_sequential (2, False, True),/** * Temporary node: After the client session fails or the connection is closed, the node is automatically deleted and cannot be created under the temporary node Build child nodes, otherwise reported as follows: Org.apache.zookeeper.keeperexception$nochildrenforephemeralsexception/ephemeral (1, TR
UE, FALSE),/** * Temporary sequential node: The basic characteristics coincide with the temporary node, in the process of creating a node, Zookeeper automatically appends a monotonically growing number suffix to the new node name after its name;
Ephemeral_sequential (3, True, true);
private static final Logger LOG = Loggerfactory.getlogger (Createmode.class);
Private Boolean ephemeral;
private Boolean sequential;
private int flag;
Createmode (int flag, Boolean ephemeral, Boolean sequential) {This.flag = flag;
This.ephemeral = ephemeral; This.sequential = sequential;
public Boolean isephemeral () {return ephemeral;
public Boolean issequential () {return sequential;
public int Toflag () {return flag;
static public createmode fromflag (int flag) throws keeperexception {switch (flag) {
Case 0:return Createmode.persistent;
Case 1:return Createmode.ephemeral;
Case 2:return createmode.persistent_sequential;
Case 3:return createmode.ephemeral_sequential;
Default:LOG.error ("Received a invalid flag value to convert to a createmode");
throw new Keeperexception.badargumentsexception (); }
}
}
Test Code:
Package zookeeper;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
Import org.apache.zookeeper.*;
Import Org.apache.zookeeper.data.Stat;
Import java.util.List;
Import java.io.IOException;
Import java.util.Collections;
Import Java.util.concurrent.CountDownLatch;
public class Distributedlock implements watcher{private int threadId;
Private zookeeper ZK = null;
Private String Selfpath;
Private String Waitpath;
Private String Log_prefix_of_thread;
private static final int session_timeout = 10000;
private static final String Group_path = "/dislocks";
private static final String Sub_path = "/dislocks/sub";
private static final String connection_string = "192.168.*.*:2181";
private static final int thread_num = 10;
Ensure the connection zk succeeds; private Countdownlatch Connectedsemaphore = new Countdownlatch (1); //Ensure that all threads run the end; private static final Countdownlatch Threadsemaphore = new Countdownlatch (thread_num);
private static final Logger LOG = Loggerfactory.getlogger (Allzookeeperwatcher.class);
public distributedlock (int id) {this.threadid = ID;
Log_prefix_of_thread = "" "+threadid+" "";
public static void Main (string[] args) {for (int i=0; i < thread_num; i++) {
Final int threadId = i+1;
New Thread () {@Override public void run () {try{
Distributedlock dc = new Distributedlock (threadId);
Dc.createconnection (connection_string, session_timeout);
If Group_path does not exist, it can be created by a thread; synchronized (Threadsemaphore) { Dc.createpath (Group_path, "This node is threaded" + THREadid + "Create", true);
} dc.getlock ();
catch (Exception e) {log.error ("" "+threadid+ Exception thrown by" thread ");
E.printstacktrace ();
}}.start ();
try {threadsemaphore.await ();
Log.info ("All threads run over!");
catch (Interruptedexception e) {e.printstacktrace (); }/** * Acquire lock * @return * * private void Getlock () throws Keepe Rexception, interruptedexception {selfpath = Zk.create (Sub_path,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, Createmo De.
Ephemeral_sequential);
Log.info (log_prefix_of_thread+ "Create Lock Path:" +selfpath);
if (Checkminpath ()) {getlocksuccess ();
}/** * Create node * @param path node path * @param data initial content * @return */Public Boolean Createpath (string path, String data, Boolean Needwatch) throws Keeperexception, Interrupte dexception {if (zk.exists (path, Needwatch) ==null) {Log.info (Log_prefix_of_thread +) node is created as
Work, Path: "+ this.zk.create (path, data.getbytes (), ZooDefs.Ids.OPEN_ACL_UNSAFE, Createmode.persistent) + ", cont
ENT: "+ data";
return true; /** * Create ZK connection * @param connectstring ZK server address List * @param sessiontimeout session Timeout Time */public void createconnection (String connectstring, int sessiontimeout) throws IOException, int erruptedexception {ZK = new zookeeper (connectstring, sesSiontimeout, this);
Connectedsemaphore.await (); /** * Acquire lock success/public void getlocksuccess () throws Keeperexception, Interruptedex ception {if (zk.exists (this.selfpath,false) = = null) {Log.error (log_prefix_of_thread+) This node has been
Not in ... ");
Return Log.info (Log_prefix_of_thread + "get lock success, work quickly.")
");
Thread.Sleep (2000);
Log.info (log_prefix_of_thread + "Delete this node:" +selfpath);
Zk.delete (This.selfpath,-1);
Releaseconnection ();
Threadsemaphore.countdown (); /** * Close ZK/public void releaseconnection () {if (This.zk!=n
ull) {try {this.zk.close ();
catch (Interruptedexception e) {}} log.info (Log_prefix_of_thread + "release Connection");
} /** * Check itself is not the smallest node * @return * * public boolean Checkminpath () throws Keepe
Rexception, interruptedexception {list<string> subnodes = Zk.getchildren (Group_path, false);
Collections.sort (subnodes);
int index = Subnodes.indexof (selfpath.substring (Group_path.length () +1));
Switch (index) {case-1:{log.error (log_prefix_of_thread+ "This node is no longer ..." +selfpath);
return false;
The case 0:{Log.info (log_prefix_of_thread+ "Child node, I really is the eldest brother" +selfpath);
return true;
} default:{This.waitpath = Group_path + "/" + Subnodes.get (index-1);
Log.info (log_prefix_of_thread+ "Get the +waitpath) in the child node, in front of me;" try{Zk.getdata (Waitpath, True,New Stat ());
return false;
}catch (keeperexception e) {if (zk.exists (waitpath,false) = = null) {
Log.info (log_prefix_of_thread+ "child node, in front of Me" +waitpath+ "has disappeared, happiness came too suddenly?");
return Checkminpath ();
}else{throw E; "}}}} @Override public void P
Rocess (Watchedevent event) {if (event = = null) {return;
} event.keeperstate keeperstate = Event.getstate ();
Event.eventtype EventType = Event.gettype ();
if (Event.KeeperState.SyncConnected = = keeperstate) {if (Event.EventType.None = = EventType) {
Log.info (Log_prefix_of_thread + "successfully connected to ZK server"); CoNnectedsemaphore.countdown ();
}else if (event.gettype () = = Event.EventType.NodeDeleted && event.getpath (). Equals (Waitpath)) { Log.info (Log_prefix_of_thread + "received the information that the guy in front of me had hung up and I was not able to get out."
");
try {if (Checkminpath ()) {getlocksuccess ();
} catch (Keeperexception e) {e.printstacktrace ();
catch (Interruptedexception e) {e.printstacktrace (); }}else if (Event.KeeperState.Disconnected = = keeperstate) {Log.inf
O (log_prefix_of_thread + "disconnect from ZK server");
else if (Event.KeeperState.AuthFailed = = keeperstate) {log.info (log_prefix_of_thread + "permission check failed");
else if (Event.KeeperState.Expired = = keeperstate) { Log.info (Log_prefix_of_thread + "session invalidation"); }
}
}
Log configuration file:
# DEFAULT Log4j.rootlogger=info,console # Log INFO level and above messages to the CONSOLE # Log4j.appender.console=org.apache.log4j.consoleappender Log4j.appender.console.threshold=info log4j.a Ppender.
Console.layout=org.apache.log4j.patternlayout log4j.appender.console.layout.conversionpattern=%d{iso8601}-%m%n
Log4j.appender.commonstat=org.apache.log4j.dailyrollingfileappender Log4j.appender.commonstat.threshold=info Log4j.appender.commonstat.file=/home/zookeeper/zookeeper-test-agent/logs/test.log Log4j.appender.COMMONSTAT.Dat Epattern= '. ' YYYY-MM-DD Log4j.appender.commonstat.layout=org.apache.log4j.patternlayout log4j.appender.commonstat.layout.c ONVERSIONPATTERN=[%D{YYYY-MM-DD HH:mm:ss}]-%m%n log4j.logger.org.displaytag=warn Log4j.logger.org.apache.zo Okeeper=error Log4j.logger.org.springframework=warn Log4j.logger.org.i0itec=warn Log4j.logger.commonStat =info, Commonstat
Run Result:
2014-11-19 11:34:10,894-"9th thread" successfully connected ZK server 2014-11-19 11:34:10,895-"8th thread" successfully connected to ZK server 2014-11-19 11:34:1 0,894-"1th thread" successfully connected to ZK server 2014-11-19 11:34:10,894-"7th thread" successfully connected ZK server 2014-11-19 11:34:10,894-"4th thread" successfully connected ZK Server 2014-11-19 11:34:10,895-"5th thread" successfully connected ZK server 2014-11-19 11:34:10,896-"2nd thread" successfully connected ZK server 2014-11-19 1 1:34:10,894-"10th thread" successfully connected to ZK server 2014-11-19 11:34:10,894-"3rd thread" successfully connected to ZK server 2014-11-19 11:34:10,895-"6th thread" Successfully connected ZK server 2014-11-19 11:34:10,910-"Thread 9th" node created successfully, Path:/dislocks, Content: This node was created by thread 9 in 2014-11-19 11:34:10,91 2-"9th thread" create lock path:/dislocks/sub0000000000 2014-11-19 11:34:10,917-"6th thread" create lock path:/dislocks/sub0000000001 2014-1 1-19 11:34:10,917-"9th Thread" child node I was the boss./dislocks/sub0000000000 2014-11-19 11:34:10,921-"3rd thread" create Lock Path:/dislocks/sub00 00000002 2014-11-19 11:34:10,922-"6th thread" Get child node, row in front of me/dislocks/sub0000000000 2014-11-19 11:34:10,923-"9th line
Process to get the lock succeeded, hurriedly work. 2014-11-19 11:34:10,924-"thread 10th" Create a lock path:/dislocks/sub0000000003 2014-11-19 11:34:10,924-"3rd thread" gets the child node, in front of me/dislocks/ sub0000000001 2014-11-19 11:34:10,928-"10th thread" Get child node, row in front of me in the/dislocks/sub0000000002 2014-11-19