Introduction and examples of redis locking mechanism

  • 2020-06-19 12:03:23
  • OfStack

A pessimistic locking

Before executing an operation, assume that the current operation is certain (or likely) to be interrupted (pessimistic). Based on this assumption, we lock the relevant resources before doing the operation and do not allow other operations to interfere with our execution.

Redis does not support pessimistic locking. When Redis is used as a cache server, it is mainly read operation, rarely write operation, and the corresponding operation is less likely to be interrupted. Pessimistic locking is not used to prevent performance degradation.

2 optimistic locking

Execute the operation assuming that the current operation will not be interrupted (optimistic). Based on this assumption, we will not lock the resource before doing the operation. If other operations interfere, the operation will be abandoned.

3. Lock policy in Redis

Redis USES an optimistic locking strategy (via the watch operation). Optimistic locking supports read operations and is suitable for situations where you read more and write less!
In transactions, locking can be done via the watch command; UNWATCH can be used to unlock;
If WATCH (locked) is executed before the transaction, the lock pair is automatically released after the EXEC or DISCARD commands are executed, i.e., UNWATCH is no longer needed

example

redis lock tool class


package com.fly.lock;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisLock {
  // Initialize the redis pool 
  private static JedisPoolConfig config;
  private static JedisPool pool;
  static {
    config = new JedisPoolConfig();
    config.setMaxTotal(30);
    config.setMaxIdle(10);
    pool = new JedisPool(config, "192.168.233.200", 6379);
  }
  /**
   *  to target locked 
   * @param target
   **/
  public static void lock(Object target) {
    // To obtain jedis
    Jedis jedis = pool.getResource();
    //result receive setnx Is the initial value of 0
    Long result= 0L;
    while (result < 1) {
      // if target in redis Already exists in, returns 0 ; Otherwise, the redis Set in the target Key value pair, and return 1
      result = jedis.setnx(target.getClass().getName() + target.hashCode(), Thread.currentThread().getName());
    }
    jedis.close();
  }
  /**
   *  to target unlock 
   * @param target
   **/
  public static void unLock(Object target) {
    Jedis jedis = pool.getResource();
    // delete redis In the target The key-value pair of the object 
    Long del = jedis.del(target.getClass().getName() + target.hashCode());
    jedis.close();
  }
  /**
   *  Try to give target Lock, if the lock returns successfully true If the lock fails to return false
   * @param target
   * @return
   **/
  public static boolean tryLock(Object target) {
    Jedis jedis = pool.getResource();
    Long row = jedis.setnx(target.getClass().getName() + target.hashCode(), "true");
    jedis.close();
    if (row > 0) {
      return true;
    }
    return false;
  }
}

The test class


package com.fly.test;
import com.fly.lock.RedisLock;
class Task {
  public void doTask() {
    // locked 
    RedisLock.lock(this);
    System.out.println(" The current thread : " + Thread.currentThread().getName());
    System.out.println(" Start to perform : " + this.hashCode());
    try {
      System.out.println("doing...");
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(" complete : " + this.hashCode());
    // unlock 
    RedisLock.unLock(this);
  }
}
public class Demo {
  public static void main(String[] args) {
    Task task = new Task();
    Thread[] threads = new Thread[5];
    for (Thread thread : threads) {
      thread = new Thread(()->{
        task.doTask();
      });
      thread.start();
    }
  }
}

Output results:

[

----------------------------------------------
Current thread: Thread-0
Start execution: 2081499965
doing...
Finish: 2081499965
----------------------------------------------
Current thread: ES50en-2
Start execution: 2081499965
doing...
Finish: 2081499965
----------------------------------------------
Current thread: ES58en-1
Start execution: 2081499965
doing...
Finish: 2081499965
----------------------------------------------
Current thread: Thread-4
Start execution: 2081499965
doing...
Finish: 2081499965
----------------------------------------------
Current thread: ES74en-3
Start execution: 2081499965
doing...
Finish: 2081499965

]

After the redis lock is removed, the execution result is:

[

----------------------------------------------
----------------------------------------------
Current thread: ES90en-2
Start execution: 1926683415
----------------------------------------------
Current thread: ES95en-1
doing...
Current thread: ES99en-0
----------------------------------------------
Current thread: Thread-3
Start execution: 1926683415
doing...
Start execution: 1926683415
doing...
----------------------------------------------
Start execution: 1926683415
doing...
Current thread: Thread-4
Start execution: 1926683415
doing...
Finish: 1926683415
Finish: 1926683415
Finish: 1926683415
Finish: 1926683415
Finish: 1926683415

]

Process finished with exit code 0

Use redis this nature, can realize the distributed lock, of course, design 1 must be more complex 1!

conclusion


Related articles: