preface

  • The redis command to get the lock

  • SET resource_name my_random_value NX PX 30000

    • (1) resource_name: indicates the resource name. Locks can be distinguished based on services
    • (2) my_random_value: a random value, different for each thread, used to release the lock corresponding to the lock
    • (3) NX: If the key does not exist, the setting succeeds. If the key does exist, the setting fails
    • (4) PX: automatic failure time, abnormal situation, lock can be released by itself.
  • Why use SETNX to implement:

    • Because of the delay between the GET and SET operations, we have no way of knowing whether other threads are also setting the lock between “sending the command” and “redis server returning the result.” Of course, this is all within milliseconds, and the probability of it happening is pretty low. But if you have a large number of concurrent threads and commands running in a busy environment, the potential for overlap is not trivial. To solve this problem, the SETNX command should be used. SETNX eliminates the problem of the GET command waiting for a return value. SETNX returns success only if the key does not exist. This means that only one thread can successfully run the SETNX command, while the others will fail and retry until they can establish the lock.

Code section

  • RedisLockController.java
@RestController @Slf4j public class RedisLockController { @Autowired private RedisTemplate redisTemplate; @requestMapping ("redisLock") public String redisLock(){log.info(" I entered method! ); Try (RedisLock RedisLock = new RedisLock(redisTemplate,"redisKey",30)){if (redislock. getLock()) {log.info(" I enter the lock!! ") ); Thread.sleep(15000); } } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } log.info(" method completed "); Return "method execution completed "; }}Copy the code
  • RedisLock.java
@Slf4j public class RedisLock implements AutoCloseable { private RedisTemplate redisTemplate; private String key; private String value; Private int expireTime; private int expireTime; public RedisLock(RedisTemplate redisTemplate,String key,int expireTime){ this.redisTemplate = redisTemplate; this.key = key; this.expireTime=expireTime; this.value = UUID.randomUUID().toString(); Public Boolean getLock(){RedisCallback<Boolean> RedisCallback = connection -> {// Set NX RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent(); // Set Expiration time Expiration Expiration = expiration. seconds(expireTime); / / serialization key byte [] redisKey = redisTemplate. GetKeySerializer (). The serialize (key); / / serialized value byte [] redisValue = redisTemplate. GetValueSerializer () serialize (value); Boolean result = connection.set(redisKey, redisValue, expiration, setOption); return result; }; Boolean lock = (Boolean) redistemplate. execute(redisCallback); return lock; } public boolean unLock() { String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" + " return redis.call(\"del\",KEYS[1])\n" + "else\n" + " return 0\n" + "end"; RedisScript<Boolean> redisScript = RedisScript.of(script,Boolean.class); List<String> keys = Arrays.asList(key); Boolean result = (Boolean)redisTemplate.execute(redisScript, keys, value); Log.info (" lock release result: "+result); return result; } @Override public void close() throws Exception { unLock(); }}Copy the code
  • Why implement the AutoCloseable interface
    • 1. Understand AutoCloseable:
      • The AutoCloseable interface is in the java.lang package and was introduced starting with JDK1.7.

    • 2. For instances of classes that implement the AutoCloseable interface, place them after a try (we call them try statements with resources). When the try ends, the resources are automatically closed (call the close method).