Home > Java > javaTutorial > body text

Detailed explanation of using Redis to implement distributed locks (code example)

不言
Release: 2018-10-20 17:00:28
forward
3459 people have browsed it

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 val
If and only if the key does not exist, set a string with key val and return 1 ; If the key exists, do nothing and return 0.

expire

expire key timeout
Set a timeout for the key in seconds. The lock will be automatically released after this time to avoid deadlock.

delete

delete key
Delete key

When 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;
    }
}
Copy after login

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);
    }
}
Copy after login

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);
}
Copy after login

It can be seen from the results that some are performed asynchronously.

Detailed explanation of using Redis to implement distributed locks (code example)

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!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template