Distributed lock is often used in distributing applications, mainly to solve the problem of distributed resource access conflict. The first thing to think about is reentrantlock, but in reality it's problematic, reentrantlock lock and unlock requirements must be on the same thread, and in distributed applications, lock and unlock are two unrelated requests, Therefore, it is certainly not the same thread, so reentrantlock cannot be used.
Then consider the use of their own state to carry out the lock state record, the results found always deadlock, carefully look at the code, can not lock dead.
1 2 3 4 5 6 7 8 9 10 11 12 |
Public synchronized void Lock () { while (lock) { Thread.Sleep (1); } Lock=true; ... }
public synchronized void unlock () { Lock=false; ... } |
The first request asks for a lock, okay, give him a lock, and then he takes the lock and goes to work.
This time, the second request also requires a lock, OK, he is in lock medium to be unlocked.
The first to finish the work, come over and lock, this time sad, because, he can't enter unlock method.
One might ask, why use while instead of wait...notify? This question, let's see if anyone can give it up.
In short, the above bin case miscarried.
Similarly, do not put synchronized on the method, directly put in the method to put a synchronization object can not? The same goes for the same deadlock.
So far the future is dark.
@ Shen Coliang Classmate's http://my.oschina.net/shenxueliang/blog/135865 wrote a with ZK do with Bushi, feeling is more complex and doubtful. Do not do it yourself, and do not forget.
Then look at the lock interface, think about it, do not follow the lock interface. The following interface has been written.
1 2 3 4 5 6 7 8 9 |
Public interface Distributedlock extends RemoteObject {
Long Lock () throws RemoteException, TimeoutException;
Long Trylock (long time, Timeunit unit) throws RemoteException, TimeoutException;
void unlock (Long token) throws remoteexception;
} |
Oh, sharp-eyed's classmates may have found a different.
The lock method adds a long return value, Trylock method, return is not a Boolean, is also the Long,unlock method more than a long parameter type parameter, oh, the technique is here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
public class Distributedlockimpl extends UnicastRemoteObject implements Distributedlock { /** * Timeout units */ Private Timeunit locktimeoutunit = timeunit.seconds; /** * Lock Tokens */ Private volatile long token = 0; /** * Synchronizing objects */ Byte[] lock = new Byte[0]; /** * Default never Expires */ Long lockTimeout = 60 * 60;//default timeout 3,600 seconds Long beginlocktime;//gets token time in milliseconds
Public Distributedlockimpl () throws RemoteException { Super (); }
/** * @param lockTimeout Lock timeout time, if lock object unlocked, automatically unlock after timeout * @param locktimeoutunit * @throws RemoteException */ Public Distributedlockimpl (Long lockTimeout, Timeunit locktimeoutunit) throws RemoteException { Super (); This.locktimeout = LockTimeout; This.locktimeoutunit = This.locktimeoutunit; } Public long Lock () throws TimeoutException { Return Trylock (0, timeunit.milliseconds); } Private Boolean islocktimeout () { if (lockTimeout <= 0) { return false; } Return (System.currenttimemillis ()-Beginlocktime) < Locktimeoutunit.tomillis (lockTimeout); } Private Long GetToken () { Beginlocktime = System.currenttimemillis (); token = System.nanotime (); return token; } Public long Trylock (long time, Timeunit unit) throws TimeoutException { Synchronized (lock) { Long startTime = System.nanotime (); while (token! = 0 && islocktimeout ()) { try { if (Time > 0) { Long endTime = System.nanotime (); if (Endtime-starttime >= Unit.tomillis (time)) { throw new TimeoutException (); } } Thread.Sleep (1); } catch (Interruptedexception e) { Do noting } } return GetToken (); } } public void unlock (long token) { if (This.token! = 0 && token = = This.token) { This.token = 0; } else { throw new RuntimeException ("token" + token + "invalid."); } } } |
Here's a little bit of code to explain.
The code above provides a lock method that waits forever for a lock and a trylock method to get the timeout exception if the lock fails at the specified time, and there is another unlock method.
The key point of the technology is actually the token, the above implementation, there is a basic assumption that the time between two remote calls can not be completed within 1 nanoseconds. Therefore, each lock operation returns a long integer token, which is the number of nanoseconds at the time of execution. The next unlock must be unlocked with the obtained token before it can be successful. Thus, unlocking does not need to add synchronization operations, so as to resolve the above deadlock problem.
In fact, there is no token is also possible, but that will result in a acquires a lock, but B execution unlock will also be successfully unlocked, is not secure, and the addition of tokens, you can guarantee that only the lock can be unlocked.
Here is the test code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public class Testdlock { public static void Main (string[] args) throws Exception { Rmiserver rmiserver = new Localrmiserver (); Distributedlockimpl Distributedlock = new Distributedlockimpl (); Rmiserver.registerremoteobject ("Lock1", Distributedlock); Multithreadprocessor processor = new Multithreadprocessor ("AA"); for (int i = 0; i < 8; i++) { Processor.addprocessor (New Runlock ("AA" + i)); } Long s = System.currenttimemillis (); Processor.start (); Long e = System.currenttimemillis (); System.out.println (e-s); Rmiserver.unexportobject (Distributedlock); } }
Class Runlock extends Abstractprocessor { Public Runlock (String name) { Super (name); }
@Override protected void action () throws Exception { try { Rmiserver client = new Remotermiserver (); Distributedlock lock = Client.getremoteobject ("Lock1"); for (int i = 0; i <; i++) { Long token = Lock.lock (); Lock.unlock (token); } System.out.println ("end-" + thread.currentthread (). GetId ()); } catch (RemoteException e) { E.printstacktrace (); } } } |
Operating conditions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 25 26 27 |
-0 [main] INFO-thread group <aa> run start, number of threads 8 ... -3 [aa-aa0] INFO-thread <aa-aa0> run start ... -3 [AA-AA1] INFO-thread <aa-aa1> run start ... -3 [AA-AA2] INFO-thread <aa-aa2> run start ... -3 [Aa-aa3] INFO-thread <aa-aa3> run start ... -3 [AA-AA4] INFO-thread <aa-aa4> run start ... -4 [AA-AA5] INFO-thread <aa-aa5> run start ... -4 [AA-AA6] INFO-thread <aa-aa6> run start ... -8 [aa-aa7] INFO-thread <aa-aa7> run start ... End-19 -9050 [Aa-aa3] INFO-thread <aa-aa3> run end End-17 -9052 [AA-AA1] INFO-thread <aa-aa1> run end End-20 -9056 [AA-AA4] INFO-thread <aa-aa4> run end End-16 -9058 [aa-aa0] INFO-thread <aa-aa0> run end End-21 -9059 [AA-AA5] INFO-thread <aa-aa5> run end End-26 -9063 [aa-aa7] INFO-thread <aa-aa7> run end End-18 -9064 [AA-AA2] INFO-thread <aa-aa2> run end End-22 -9065 [AA-AA6] INFO-thread <aa-aa6> run end -9066 [main] INFO-thread group <aa> run end, spents: 9065ms 9069 |
That is, 8,000 locks and unlocks are performed in 9069ms.
Summary:
Above the implementation of the distributed lock scheme, comprehensive consideration of the implementation of simple, lock security, lock timeout and other factors. The actual test, about 900 to 1000 times for lock and release lock operations per second, can meet most application requirements.
As a result of yesterday powder request issued as soon as possible, so the more hurried, deficiencies and bugs are unavoidable, welcome to shoot bricks.
Simple implementation of distributed locks