All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.voovan.tools.collection.RedisLock Maven / Gradle / Ivy

There is a newer version: 4.3.8
Show newest version
package org.voovan.tools.collection;

import org.voovan.tools.TEnv;
import org.voovan.tools.TString;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Collections;

/**
 * 基于 Redis 的分布式锁
 *
 * @author: helyho
 * DBase Framework.
 * WebSite: https://github.com/helyho/DBase
 * Licence: Apache v2 License
 */
public class RedisLock {
    private JedisPool redisPool;
    private String lockName = null;
    private int dbIndex = 0;
    private String lockValue = TString.generateShortUUID();;

    /**
     * 构造函数
     * @param host        redis 服务地址
     * @param port        redis 服务端口
     * @param timeout     redis 连接超时时间
     * @param poolsize    redis 连接池的大小
     * @param lockName        锁的键名
     * @param password    redis 服务密码
     */
    public RedisLock(String host, int port, int timeout, int poolsize, String lockName, String password){
        super();

        //如果没有指定JedisPool的配置文件,则使用默认的
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(poolsize);
        poolConfig.setMaxTotal(poolsize);

        //如果没有指定密码,则默认不需要密码
        if(password==null) {
            redisPool = new JedisPool(poolConfig, host, port, timeout);
        }else {
            redisPool = new JedisPool(poolConfig, host, port, timeout, password);
        }
        this.lockName = lockName;
    }

    /**
     * 构造函数
     * @param host        redis 服务地址
     * @param port        redis 服务端口
     * @param timeout     redis 连接超时时间
     * @param poolsize    redis 连接池的大小
     * @param lockName        锁的键名称
     */
    public RedisLock(String host, int port, int timeout, int poolsize, String lockName){
        super();

        //如果没有指定JedisPool的配置文件,则使用默认的
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(poolsize);
        poolConfig.setMaxTotal(poolsize);

        redisPool = new JedisPool(poolConfig, host, port, timeout);
        this.lockName = lockName;
    }

    /**
     * 构造函数
     * @param lockName 锁的键名
     */
    public RedisLock(String lockName){
        this.redisPool = CacheStatic.getDefaultRedisPool();
        this.lockName = lockName;
    }

    /**
     * 构造函数
     * @param jedisPool redis 连接池
     * @param name 在 redis 中的 HashMap的名称
     */
    public RedisLock(JedisPool jedisPool, String name){
        this.redisPool = jedisPool;
        this.lockName = lockName;
    }

    /**
     * 构造函数
     * @param jedisPool redis 连接池
     */
    public RedisLock(JedisPool jedisPool){
        this.redisPool = jedisPool;
    }

    /**
     * 获取当前选择的数据集
     * @return 数据集序号
     */
    public int getDbIndex() {
        return dbIndex;
    }

    /**
     * 选择当前数据集
     * @param dbIndex 数据集序号
     */
    public void setDbIndex(int dbIndex) {
        this.dbIndex = dbIndex;
    }

    private Jedis getJedis(){
        Jedis Jedis = redisPool.getResource();
        Jedis.select(dbIndex);
        return Jedis;
    }

    /**
     * 尝试加锁
     *      快速失败的方式
     * @param lockValue 锁的值
     * @param lockExpireTime 锁的超时时间
     * @return true: 成功, false: 失败
     */
    public boolean tryLock(String lockValue, int lockExpireTime){

        if(lockValue==null){
            lockValue = String.valueOf(System.currentTimeMillis());
        }

        try (Jedis jedis = getJedis()) {
            String result = jedis.set(this.lockName, lockValue, RedisMap.SET_NOT_EXIST, RedisMap.SET_EXPIRE_TIME, lockExpireTime);
            this.lockValue = lockValue;

            if ( RedisMap.LOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        }
    }

    /**
     * 尝试加锁
     *      快速失败的方式
     * @param lockExpireTime 超时时间
     * @return true: 成功, false: 失败
     */
    public boolean tryLock(int lockExpireTime){
        return tryLock(null, lockExpireTime);
    }

    /**
     * 尝试加锁
     *      超时时间 timewait 是尝试加锁的最长时间
     * @param lockValue 锁的名称
     * @param lockExpireTime 锁的键值对的超时时间
     * @param timewait 获取锁的等待时间, 单位: 毫秒
     * @return true: 成功, false: 失败
     */
    public boolean lock(String lockValue, int lockExpireTime, int timewait){

        if(lockValue==null){
            lockValue = this.lockValue;
        }

        long start = System.currentTimeMillis();
        while(true) {
            try (Jedis jedis = getJedis()) {
                String result = jedis.set(this.lockName, lockValue,  RedisMap.SET_NOT_EXIST,  RedisMap.SET_EXPIRE_TIME, lockExpireTime);

                if (RedisMap.LOCK_SUCCESS.equals(result)) {
                    return true;
                }

                if(System.currentTimeMillis() - start > timewait){
                    break;
                }

                TEnv.sleep(1);
                continue;
            }
        }

        return false;
    }

    /**
     * 尝试加锁
     *      超时时间 timewait 是尝试加锁的最长时间
     * @param lockExpireTime 锁的键值对的超时时间
     * @param timewait 获取锁的等待时间, 单位: 毫秒
     * @return true: 成功, false: 失败
     */
    public boolean lock(int lockExpireTime, int timewait){
        return lock(null, lockExpireTime, timewait);
    }

    /**
     * 释放锁
     * @return true: 成功, false: 失败
     */
    public boolean unLock() {

        try (Jedis jedis = getJedis()) {
            String script = "if redis.call('getThread', KEYS[1]) == ARGV[1] then " +
                                "return redis.call('del', KEYS[1]) " +
                            "else " +
                                "return 0 " +
                            "end";
            Object result = jedis.eval(script, Collections.singletonList(this.lockName), Collections.singletonList(lockValue));

            if ( RedisMap.UNLOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        }

    }

    /**
     * 释放锁
     * @param lockValue 锁的名称
     * @return true: 成功, false: 失败
     */
    public boolean unLock(String lockValue) {

        try (Jedis jedis = getJedis()) {
            String script = "if redis.call('getThread', KEYS[1]) == ARGV[1] then " +
                                "return redis.call('del', KEYS[1]) " +
                            "else " +
                                "return 0 " +
                            "end";
            Object result = jedis.eval(script, Collections.singletonList(this.lockName), Collections.singletonList(this.lockValue));

            if ( RedisMap.UNLOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy