Blog.csdn.net/l_bestcoder…

What is distributed lock?

To introduce distributed locks, we must first mention that the corresponding distributed locks are thread locks and process locks.

Thread lock: used to lock methods and code blocks. When a method or code uses a lock, only one thread executes the method or code segment at a time. Thread locks are only effective within the same JVM, because implementation of thread locks is fundamentally based on shared memory between threads, such as synchronized, which is a shared object header, and Lock, which is a shared variable (state).

Process lock: To control the access of multiple processes in the same operating system to a shared resource, processes are independent and cannot access resources of other processes. Therefore, thread locks such as synchronized cannot be used to implement process locks.

Distributed lock: When multiple processes are not in the same system, a distributed lock is used to control the access of multiple processes to resources.

Second, the use scenario of distributed lock.

Both interthread and interprocess concurrency problems can be solved by distributed locking, but this is strongly discouraged! Because solving these small problems with distributed locks is very resource-intensive! Distributed locks are most appropriate for solving the problem of multi-process concurrency in distributed situations.

There is A situation where thread A and thread B both share some variable X.

In the case of a single machine (single JVM), where memory is shared between threads, the concurrency problem can be solved by simply using thread locks.

In distributed (multi-JVM) situations, thread A and thread B are most likely not in the same JVM, and thus the thread lock will not work, so the distributed lock will be used to solve the problem.

Three, distributed lock implementation (Redis)

The key to realize distributed lock is to build a storage server outside the distributed application server to store lock information. At this time, we can easily think of Redis. First we need to build a Redis server, with Redis server to store lock information.

A few key points to note when implementing:

1, lock information must be expired timeout, can not let a thread hold a lock for a long time to cause deadlock;

2. Only one thread can acquire the lock at a time.

A few redis commands to use:

Setnx (key, value) : “Set if not exits”. If the key-value does not exist, it is successfully added to the cache and returns 1. Otherwise, 0 is returned.

Get (key) : Gets the value of the key, or returns nil if none exists.

Getset (key, value) : gets the value of the key, returns nil if it does not exist, and then updates the old value to the new value.

Expire (key, seconds) : Sets the validity period of key-value to seconds.

Take a look at the flow chart:

\

Under this process, no deadlock is caused.

I use Jedis as the Redis client API, the following is to see the specific implementation of the code.

(1) First create a Redis connection pool.

[java]  view plain  copy

  1. public class RedisPool {  
  2.   
  3. private static JedisPool pool; / / jedis connection pool
  4.   
  5. private static int maxTotal = 20; // Maximum number of connections
  6.   
  7. private static int maxIdle = 10; // Maximum number of idle connections
  8.   
  9. private static int minIdle = 5; // Minimum number of free connections
  10.   
  11. private static boolean testOnBorrow = true; // Test connection availability when fetching a connection
  12.   
  13. private static boolean testOnReturn = false; // The availability of the connection is not tested when reconnecting
  14.   
  15.     static {  
  16. initPool(); // Initialize the connection pool
  17.     }  
  18.   
  19.     public static Jedis getJedis(){  
  20.         return pool.getResource();  
  21.     }  
  22.   
  23.     public static void close(Jedis jedis){  
  24.         jedis.close();  
  25.     }  
  26.   
  27.     private static void initPool(){  
  28.         JedisPoolConfig config = new JedisPoolConfig();  
  29.         config.setMaxTotal(maxTotal);  
  30.         config.setMaxIdle(maxIdle);  
  31.         config.setMinIdle(minIdle);  
  32.         config.setTestOnBorrow(testOnBorrow);  
  33.         config.setTestOnReturn(testOnReturn);  
  34.         config.setBlockWhenExhausted(true);  
  35. Pool = new JedisPool(config, “127.0.0.1”, 6379, 5000, “liqiyao”);
  36.     }  
  37. }  

(2) Encapsulate Jedis API to encapsulate some operations needed to achieve distributed lock.

[java]  view plain  copy

  1. public class RedisPoolUtil {  
  2.   
  3.     private RedisPoolUtil(){}  
  4.   
  5.     private static RedisPool redisPool;  
  6.   
  7.     public static String get(String key){  
  8.         Jedis jedis = null;  
  9.         String result = null;  
  10.         try {  
  11.             jedis = RedisPool.getJedis();  
  12.             result = jedis.get(key);  
  13.         } catch (Exception e){  
  14.             e.printStackTrace();  
  15.         } finally {  
  16. if (jedis ! = null) {
  17.                 jedis.close();  
  18.             }  
  19.             return result;  
  20.         }  
  21.     }  
  22.   
  23.     public static Long setnx(String key, String value){  
  24.         Jedis jedis = null;  
  25.         Long result = null;  
  26.         try {  
  27.             jedis = RedisPool.getJedis();  
  28.             result = jedis.setnx(key, value);  
  29.         } catch (Exception e){  
  30.             e.printStackTrace();  
  31.         } finally {  
  32. if (jedis ! = null) {
  33.                 jedis.close();  
  34.             }  
  35.             return result;  
  36.         }  
  37.     }  
  38.   
  39.     public static String getSet(String key, String value){  
  40.         Jedis jedis = null;  
  41.         String result = null;  
  42.         try {  
  43.             jedis = RedisPool.getJedis();  
  44.             result = jedis.getSet(key, value);  
  45.         } catch (Exception e){  
  46.             e.printStackTrace();  
  47.         } finally {  
  48. if (jedis ! = null) {
  49.                 jedis.close();  
  50.             }  
  51.             return result;  
  52.         }  
  53.     }  
  54.   
  55.     public static Long expire(String key, int seconds){  
  56.         Jedis jedis = null;  
  57.         Long result = null;  
  58.         try {  
  59.             jedis = RedisPool.getJedis();  
  60.             result = jedis.expire(key, seconds);  
  61.         } catch (Exception e){  
  62.             e.printStackTrace();  
  63.         } finally {  
  64. if (jedis ! = null) {
  65.                 jedis.close();  
  66.             }  
  67.             return result;  
  68.         }  
  69.     }  
  70.   
  71.     public static Long del(String key){  
  72.         Jedis jedis = null;  
  73.         Long result = null;  
  74.         try {  
  75.             jedis = RedisPool.getJedis();  
  76.             result = jedis.del(key);  
  77.         } catch (Exception e){  
  78.             e.printStackTrace();  
  79.         } finally {  
  80. if (jedis ! = null) {
  81.                 jedis.close();  
  82.             }  
  83.             return result;  
  84.         }  
  85.     }  
  86. }  

(3) Distributed lock tool class

[java]  view plain  copy

  1. public class DistributedLockUtil {  

  2.   

  3.     private DistributedLockUtil(){  

  4.     }  

  5.   

  6.     public static boolean lock(String lockName){

    //lockName can be a shared variable name or a method name, mainly used to simulate lock information

  7. System.out.println(thread.currentThread () +” );

  8.         Long result = RedisPoolUtil.setnx(lockName, String.valueOf(System.currentTimeMillis() + 5000));  

  9. if (result ! = null && result.intValue() == 1){

  10. System.out.println(thread.currentThread () + “lock successful!” );

  11.             RedisPoolUtil.expire(lockName, 5);  

  12. System.out.println(thread.currentThread () + “Execute business logic!” );

  13.             RedisPoolUtil.del(lockName);  

  14.             return true;  

  15.         } else {  

  16.             String lockValueA = RedisPoolUtil.get(lockName);  

  17. if (lockValueA ! = null && Long.parseLong(lockValueA) >= System.currentTimeMillis()){

  18.                 String lockValueB = RedisPoolUtil.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));  

  19.                 if (lockValueB == null || lockValueB.equals(lockValueA)){  

  20. System.out.println(thread.currentThread () + “lock successful!” );

  21.                     RedisPoolUtil.expire(lockName, 5);  

  22. System.out.println(thread.currentThread () + “Execute business logic!” );

  23.                     RedisPoolUtil.del(lockName);  

  24.                     return true;  

  25.                 } else {  

  26.                     return false;  

  27.                 }  

  28.             } else {  

  29.                 return false;  

  30.             }  

  31.         }  

  32.     }  

  33. }  

\

Copyright notice: This article is the blogger’s original article, shall not be reproduced without the permission of the blogger. Blog.csdn.net/L_BestCoder…

\