In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
Today, I will talk to you about how to use Redis to achieve distributed locks in Java. Many people may not know much about it. In order to make you understand better, the editor has summarized the following for you. I hope you can get something from this article.
The lock can be acquired immediately. If true is returned, if not, false is returned.
Support waiting to acquire lock mode. If you get it, return true directly. If you do not wait for a short period of time, try again and again in this short period of time. If the attempt is successful, return true. If you cannot get it after the waiting time, return false.
A situation in which a deadlock cannot occur.
Cannot release locks that are not self-added
Let's use an example to demonstrate the implementation of distributed locking service using redis in Java
Add lock
The locking logic for implementing distributed locks through redis is as follows:
Redis distributed Lock implementation Logic
According to this logic, the core code to implement locking is as follows:
Jedis.select (dbIndex); String key = KEY_PRE + key;String value = fetchLockValue (); if (jedis.exists (key)) {jedis.set (key,value); jedis.expire (key,lockExpirseTime); return value;}
On the face of it, there seems to be nothing wrong with this code, but in fact it does not correctly implement locking in a distributed environment. In order to correctly implement the locking operation, the three steps of "judging the existence of key", "saving key-value" and "setting the expiration time of key" must be atomic operations. If it is not an atomic operation, the following two situations may occur:
After the step of "judging whether the key exists" shows that the key does not exist, and before the "save key-value" step, another client executes the same logic and executes the "determine whether the key exists" step, and also obtains the result that the key does not exist. This results in multiple clients acquiring the same lock.
After the client completes the "save key-value" step, you need to set a key expiration time to prevent the client from deadlock because the code quality is not unlocked, or the process crashes. After the "Save key-value" step, and before the "set key expiration time" step, the process may crash, causing the "set key expiration time" step to fail
Redis extends the set command after version 2.6.12 to circumvent the above two problems. The parameters of the new redis set command are as follows
SET key value [EX seconds] [PX milliseconds] [NX | XX]
The new version of the set command adds EX, PX, NX | XX parameter options. What they mean is as follows
EX seconds-sets the expiration time of key key, unit second PX milliseconds-sets the expiration time of key key, unit millisecond NX-sets the value of key only if the key key does not exist XX-sets the value of key only if the key key exists
In this way, the original three-step operation can be done in an atomic operation of set, avoiding the two problems mentioned above. The new version of the redis lock core code is modified as follows:
Jedis = redisConnection.getJedis (); jedis.select (dbIndex); String key = KEY_PRE + key;String value = fetchLockValue (); if ("OK" .equals (jedis.set (key, value, "NX", "EX", lockExpirseTime)) {return value;} unlock
The basic process of unlocking is as follows:
Redis distributed Lock unlocking implementation Logic
According to this logic, the core code to unlock in Java is as follows:
Jedis.select (dbIndex); String key = KEY_PRE + key;if (jedis.exists (key) & & value.equals (jedis.get (key) {jedis.del (key); return true;} return false
As when adding a lock, the three steps of whether the key exists, whether you hold the lock or not, and deleting the key-value need to be atomic, otherwise, when a client completes the step of "judging whether you hold a lock", it comes to the conclusion that you hold a lock. At this time, the expiration time of the lock is up, and it is automatically released by redis. At the same time, another client successfully locks based on this key. If the first client continues to delete the key-value, it releases the lock that does not belong to it. This obviously doesn't work. Here we take advantage of redis's ability to execute Lua scripts to solve the problem of atomic operations. The modified unlock core code is as follows:
Jedis.select (dbIndex); String key = KEY_PRE + key;String command = "if redis.call ('get',KEYS [1]) = ARGV [1] then return redis.call (' del',KEYS [1]) else return 0 end"; if (1L.equals (jedis.eval (command, Collections.singletonList (key), Collections.singletonList (value) {return true;}
In addition, the mechanism to determine whether you hold a lock is to use the key-value when you add the lock to determine whether the value of the current key is equal to the value obtained when you hold the lock. So the value when locking must be a globally unique string.
The complete code is as follows, package com.x9710.common.redis.impl;import com.x9710.common.redis.LockService;import com.x9710.common.redis.RedisConnection;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import redis.clients.jedis.Jedis;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Collections;import java.util.Date;import java.util.UUID / * distributed lock redis implementation * * @ author Yang Gaochao * @ since 2017-12-14 * / public class LockServiceRedisImpl implements LockService {private static Log log = LogFactory.getLog (LockServiceRedisImpl.class); private static String SET_SUCCESS = "OK"; private static String KEY_PRE = "REDIS_LOCK_"; private DateFormat df = new SimpleDateFormat ("yyyyMMddHHmmssSSS"); private RedisConnection redisConnection;private Integer dbIndex;private Integer lockExpirseTime;private Integer tryExpirseTime;public void setRedisConnection (RedisConnection redisConnection) {this.redisConnection = redisConnection } public void setDbIndex (Integer dbIndex) {this.dbIndex = dbIndex;} public void setLockExpirseTime (Integer lockExpirseTime) {this.lockExpirseTime = lockExpirseTime;} public void setTryExpirseTime (Integer tryExpirseTime) {this.tryExpirseTime = tryExpirseTime;} public String lock (String key) {Jedis jedis = null; try {jedis = redisConnection.getJedis (); jedis.select (dbIndex); key = KEY_PRE + key; String value = fetchLockValue () If (SET_SUCCESS.equals (jedis.set (key, value, "NX", "EX", lockExpirseTime)) {log.debug ("Reids Lock key:" + key + ", value:" + value); return value;}} catch (Exception e) {e.printStackTrace ();} finally {if (jedis! = null) {jedis.close () Return null;} public String tryLock (String key) {Jedis jedis = null; try {jedis = redisConnection.getJedis (); jedis.select (dbIndex); key = KEY_PRE + key; String value = fetchLockValue (); Long firstTryTime = new Date (). GetTime () Do {if (SET_SUCCESS.equals (jedis.set (key, value, "NX", "EX", lockExpirseTime)) {log.debug ("Reids Lock key:" + key + ", value:" + value); return value;} log.info ("Redis lock failure,waiting try next") Try {Thread.sleep;} catch (InterruptedException e) {e.printStackTrace ();}} while ((new Date (). GetTime ()-tryExpirseTime * 1000) < firstTryTime);} catch (Exception e) {e.printStackTrace () } finally {if (jedis! = null) {jedis.close ();}} return null;} public boolean unLock (String key, String value) {Long RELEASE_SUCCESS = 1L; Jedis jedis = null; try {jedis = redisConnection.getJedis (); jedis.select (dbIndex); key = KEY_PRE + key String command = "if redis.call ('get',KEYS [1]) = ARGV [1] then return redis.call (' del',KEYS [1]) else return 0 end"; if (RELEASE_SUCCESS.equals (jedis.eval (command, Collections.singletonList (key), Collections.singletonList (value) {return true;} catch (Exception e) {e.printStackTrace () } finally {if (jedis! = null) {jedis.close ();}} return false;} / * generate a locked unique string * * @ return unique string * / private String fetchLockValue () {return UUID.randomUUID (). ToString () + "_" + df.format (new Date ());}} test code package com.x9710.common.redis.test Import com.x9710.common.redis.RedisConnection;import com.x9710.common.redis.impl.LockServiceRedisImpl;public class RedisLockTest {public static void main (String [] args) {for (int I = 0; I < 9; iTunes +) {new Thread (new Runnable () {public void run () {RedisConnection redisConnection = RedisConnectionUtil.create (); LockServiceRedisImpl lockServiceRedis = new LockServiceRedisImpl (); lockServiceRedis.setRedisConnection (redisConnection)) LockServiceRedis.setDbIndex (15); lockServiceRedis.setLockExpirseTime (20); String key = "20171228"; String value = lockServiceRedis.lock (key) Try {if (value! = null) {System.out.println (Thread.currentThread (). GetName () + "lock key =" + key + "success!"); Thread.sleep (25 * 1000) } else {System.out.println (Thread.currentThread (). GetName () + "lock key =" + key + "failure!");}} catch (Exception e) {e.printStackTrace () } finally {if (value = = null) {value = ";} System.out.println (Thread.currentThread () .getName () +" unlock key = "+ key +"+ lockServiceRedis.unLock (key, value));} .start () }}}
Test result
Thread-1 lock key = 20171228 failure! Thread-2 lock key = 20171228 failure! Thread-4 lock key = 20171228 failure! Thread-8 lock key = 20171228 failure! Thread-7 lock key = 20171228 failure! Thread-3 lock key = 20171228 failure! Thread-5 lock key = 20171228 failure! Thread-0 lock key = 20171228 failure! Thread-6 lock key = 20171228 success! Thread-1 unlock key = 20171228 falseThread-2 unlock key = 20171228 falseThread-4 unlock key = 20171228 falseThread-8 unlock key = 20171228 falseThread-3 unlock key = 20171228 falseThread-5 unlock key = 20171228 falseThread-0 unlock key = 20171228 falseThread-7 unlock key = 20171228 falseThread-6 unlock key = 20171228 true after reading the above, do you have any further understanding of how to use Redis to implement distributed locks in Java? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 295
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.