This article brings you a detailed explanation (code example) of using Redis to implement distributed locks. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
Reasons for choosing Redis to implement distributed locks
Redis has high performance
The Redis command supports this better and is more convenient to implement
Introduction to using commands
SETNX
SETNX key valexpire
expire key timeoutdelete
delete keyWhen using Redis to implement distributed locks, these three commands are mainly used.
Implementation
uses jedis to connect to Redis.
Implementation Idea
When acquiring a lock, use setnx to lock it, and use the expire command to add a timeout period to the lock. After this time, the lock will be automatically released. The value is a randomly generated UUID, which is used to determine when the lock is released.
When acquiring the lock, a timeout period is also set for acquisition. If this time is exceeded, acquisition of the lock will be given up.
When releasing a lock, use the UUID to determine whether it is the lock. If it is the lock, execute delete to release the lock.
The core code of the distributed lock is as follows:
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.Transaction; import redis.clients.jedis.exceptions.JedisException; import java.util.List; import java.util.UUID; public class DistributedLock { private final JedisPool jedisPool; public DistributedLock(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** * 加锁 * @param locaName 锁的key * @param acquireTimeout 获取超时时间 * @param timeout 锁的超时时间 * @return 锁标识 */ public String lockWithTimeout(String locaName, long acquireTimeout, long timeout) { Jedis conn = null; String retIdentifier = null; try { // 获取连接 conn = jedisPool.getResource(); // 随机生成一个value String identifier = UUID.randomUUID().toString(); // 锁名,即key值 String lockKey = "lock:" + locaName; // 超时时间,上锁后超过此时间则自动释放锁 int lockExpire = (int)(timeout / 1000); // 获取锁的超时时间,超过这个时间则放弃获取锁 long end = System.currentTimeMillis() + acquireTimeout; while (System.currentTimeMillis() results = transaction.exec(); if (results == null) { continue; } retFlag = true; } conn.unwatch(); break; } } catch (JedisException e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } return retFlag; } }
Test
The following is a simple example to test the distributed lock just implemented.
In the example, 50 threads are used to simulate a flash sale of a product, and the -- operator is used to reduce the product. From the order of the results, it can be seen whether it is in a locked state.
Simulate the flash sale service, configure the jedis thread pool in it, and pass it to the distributed lock during initialization for its use.
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class Service { private static JedisPool pool = null; static { JedisPoolConfig config = new JedisPoolConfig(); // 设置最大连接数 config.setMaxTotal(200); // 设置最大空闲数 config.setMaxIdle(8); // 设置最大等待时间 config.setMaxWaitMillis(1000 * 100); // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的 config.setTestOnBorrow(true); pool = new JedisPool(config, "127.0.0.1", 6379, 3000); } DistributedLock lock = new DistributedLock(pool); int n = 500; public void seckill() { // 返回锁的value值,供释放锁时候进行判断 String indentifier = lock.lockWithTimeout("resource", 5000, 1000); System.out.println(Thread.currentThread().getName() + "获得了锁"); System.out.println(--n); lock.releaseLock("resource", indentifier); } }
Simulating threads for flash killing service
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { this.service = service; } @Override public void run() { service.seckill(); } } public class Test { public static void main(String[] args) { Service service = new Service(); for (int i = 0; i <p>The results are as follows, and the results are in order. </p><p style="text-align: center;"><span class="img-wrap"><img src="https://img.php.cn//upload/image/211/984/157/1540025904941327.png" title="1540025904941327.png" alt="Detailed explanation of using Redis to implement distributed locks (code example)"></span></p><p>If you comment out the part that uses locks</p><pre class="brush:php;toolbar:false">public void seckill() { // 返回锁的value值,供释放锁时候进行判断 //String indentifier = lock.lockWithTimeout("resource", 5000, 1000); System.out.println(Thread.currentThread().getName() + "获得了锁"); System.out.println(--n); //lock.releaseLock("resource", indentifier); }
It can be seen from the results that some are performed asynchronously.
In a distributed environment, it is sometimes important to lock resources, such as snapping up a certain resource. In this case, use distributed Locks can provide good control over resources.
Of course, in specific use, many factors need to be considered, such as the selection of timeout time and the selection of lock acquisition time, which have a great impact on the amount of concurrency. The distributed lock implemented above is just a kind of Simple implementation is mainly an idea.
[Actually, the reliability of using zookeeper is greater than the distributed lock implemented by redis, but in comparison, the performance of redis is better. ]
The above is the detailed content of Detailed explanation of using Redis to implement distributed locks (code example). For more information, please follow other related articles on the PHP Chinese website!