Redis Implement distributed lock
In the cluster and other multiple servers often used to synchronize the business, then the ordinary transaction is to meet the needs of the business, the need for distributed locks. Distributed locks are implemented in a variety of ways, such as redis implementation of distributed locks, zookeeper implementation of distributed locks, the first implementation of the Redis distributed locks. Implementation Principle
1, through SETNX (lock_timeout), if the lock is set to return 1, there is already a value does not set a successful return of 0.
2, deadlock problem: Through the time to determine whether the expiration, if it has expired, get to the expiration Time got (Lockkey), and then Getset (LOCK_TIMEOUT) to determine whether and get the same, the same proof has been locked successfully, Because it may cause multiple threads to execute the Getset (lock_timeout) method concurrently. This is likely to cause multiple threads to simply getset, to determine the lock success of the thread, plus expire (Lockkey, lock_timeout, timeunit.milliseconds) expiration time, prevent multiple threads simultaneously superimposed time, Lead to a doubling of the lock aging time.
3, for the cluster server time inconsistency problem, you can call Redis time () to get the current times. Code Implementation Distributed Lock Interface
Distributionlock.java
/**
* Creation Date: December 8, 2016 PM 6:51:51 * * *
Distributed lock
* *
@author Andy
* @version
2.2
/Public Interface Distributionlock {
//Lock successfully returned lock time public
long Lock (String lockkey, String threadname);
Unlocking requires more locking time to determine whether there are permissions to public
void unlock (String lockkey, Long Lockvalue, string threadname);
implementation of distributed lock Redis
Redisdistributionlock.java
Import java.io.Serializable;
Import Java.util.concurrent.TimeUnit;
Import Org.apache.log4j.Logger;
Import org.springframework.dao.DataAccessException;
Import org.springframework.data.redis.connection.RedisConnection;
Import Org.springframework.data.redis.core.RedisCallback;
Import Org.springframework.data.redis.core.RedisTemplate;
Import Org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
Import Org.andy.utils.SpringContextHolder; /** * Creation Time: December 8, 2016 PM 5:44:16 * * Redis Distributed Lock * * @author Andy * @version 2.2/public class REDISDISTRIBUTIONL Ock implements distributionlock{private static final long lock_timeout = 60 * 1000;//Gartha time per unit millisecond means that the operation is performed within the lock period if it is not Completion will have concurrent phenomena private static final Logger LOG = Logger.getlogger (Redisdistributionlock.class); Redis Lock Log @SuppressWarnings ("unchecked") private static redistemplate<serializable, serializable> Redistem Plate = (redistemplate<serializable, serializable>) springcontextholder
. Getbean ("Redistemplate"); /** * to lock and lock and wait until the lock is acquired/@Override public Long Lock (string lockkey, String threadname) {LOG
. info (threadname + "Start the lock"); while (true) {//Loop fetch lock Long lock_timeout = System.currenttimemillis () + lock_timeout + 1;//Lock time if (Redistemplate.execute new rediscallback<boolean> () {@Override public Boolean DoI Nredis (redisconnection connection) throws DataAccessException {Jdkserializationredisserializer Jdkser
Ializer = new Jdkserializationredisserializer ();
byte[] Value = jdkserializer.serialize (lock_timeout);
Return Connection.setnx (Lockkey.getbytes (), value);
}) {//If the lock succeeds Log.info (ThreadName + lock successful ++++++++111111111); Redistemplate.expire (Lockkey, Lock_timeout, timeunit.milliseconds); Set timeout time, free memory return lock_timeout;
}else {Long currt_lock_timeout_str = (long) redistemplate.opsforvalue (). get (Lockkey);//Redis time
if (currt_lock_timeout_str!= null && currt_lock_timeout_str < System.currenttimemillis ()) {//Lock is invalid If you decide whether it is null or empty, the description has been invalidated, and if the value is set by another thread, the second condition is that it cannot execute Long old_lock_timeout_str = (L
ONG) Redistemplate.opsforvalue (). Getandset (Lockkey, lock_timeout); Gets the last lock expiration time and sets the current lock expiration if (old_lock_timeout_str!= null && old_lock_timeout_str.equals (curr T_LOCK_TIMEOUT_STR)) {//As of this time, multiple threads happen to be here, but only one thread has the same set value as the current value, and he has the right to acquire the lock L
Og.info (ThreadName + "lock success +++++++2222222222"); Redistemplate.expire (Lockkey, Lock_timeout, timeunit.milliseconds);
Set timeout time, free memory return lock_timeout;//back Lock Time}}
try { Log.info (threadname + "Wait for lock, sleep 100 milliseconds"); TimeUnit.MILLISECONDS.sleep (100);//Sleep 100 milliseconds} catch (Interruptedexception e) {E.printstacktrac
E (); @Override public void Unlock (string lockkey, Long Lockvalue, string threadname) {LOG. Info (threadname + "perform unlock ==========");/normal direct deletion if an exception is closed, the lock determines the expiration time long currt_lock_timeout_str = (long) redistemplate. Opsforvalue (). get (Lockkey); Redis time if (currt_lock_timeout_str!= null && currt_lock_timeout_str = = Lockvalue) {//If lock is added, delete lock if is not waiting for automatic expiration of the re-competition lock Redistemplate.delete (Lockkey);
Delete key Log.info (ThreadName + "unlock successful-----------------"); }
}
}
Note: the above interface parameter ThreadName just to test the multithreading data printing, the generation environment can remove the interface Distributionlock and implement class Redisdistributionlock string ThreadName parameter.
Multiple servers take Redis time instead of all the current time System.currenttimemillis () used above.
Public long Currttimefromredis () {//Get Redis Current time return
Redistemplate.execute (new rediscallback<long> () {
@Override public
Long Doinredis (redisconnection connection) throws DataAccessException {
return Connection.time ();}}
);
Simulation Test
Test Code
Simulate 20 threads executing the business at the same time, obtaining resources.
@Test public
void Testredisdistributionlock () {for
(int i = 0; i < i++) {
new Thread (new Runnable () {
@Override public
void Run () {
task (Thread.CurrentThread (). GetName ());
}
}). Start ();
}
try {
TimeUnit.MINUTES.sleep (1);
} catch (Interruptedexception e) {
e.printstacktrace ()}
}
private void Task (String name) {
Distributionlock lock = new Redisdistributionlock ();
Long Locktime; Lock Time
if ((Locktime = Lock.lock (rediskeyutil.distributed_lock_no + 1, name))!= null) {
//start Task
SYSTEM.OUT.PRINTLN (name + "task Execution");
Task execution closes lock
lock.unlock (rediskeyutil.distributed_lock_no + 1, locktime, name);
}
Test Results
Lock ensures that only one thread acquires the current resource and frees the resource after releasing the lock.
Have time to write zookeeper implement distributed locks