一、引入的包

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.2.0</version>
</dependency>

二、加锁,释放锁方法实现

public class RedisLock {

    private static JedisPool jedisPool;

//    private static Jedis jedis = new JedisPool("192.168.118.128", 3399).getResource();
    private static final Logger logger = LoggerFactory.getLogger(RedisLock.class);

    static {
        // 初始化连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(20);
        jedisPoolConfig.setMaxIdle(10);
        jedisPool = new JedisPool(jedisPoolConfig, "192.168.118.128", 6379);
    }

    /**
     * 循环获得一个锁
     */
    public void lock(String key, String value){
        for(; ;){ // 通过循环来实现阻塞
            if(tryLock(key, value)){
                return;
            }
            try{
                TimeUnit.MILLISECONDS.sleep(100);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    /**
     * 尝试加锁
     * @param key  设置redis的key
     * @param value 通过uuid生成的唯一值,用于判断是不是锁的持有者,因为只有自己才能释放锁
     * @return
     */
    public boolean tryLock(String key, String value){
        Jedis jedis = jedisPool.getResource();
        // 设置默认超时时间(nx,px命令的合集)
        SetParams setParams = SetParams.setParams().nx().px(4_000);
//        Jedis jedis = jedisPool.getResource();
        // 设置key和值(加锁操作)
        String set = jedis.set(key, value, setParams);
        if("OK".equals(set)){
           Thread thread = new Thread(() -> {
                while (true){
                    try {
                        // 开启一个守护线程1s检测一下超时时间
                        TimeUnit.SECONDS.sleep(1);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    // 获取当前超时时间
                    Long pttl = jedis.pttl(key);
                    // 当超时时间小于1/2时,增加超时时间到原来的4s
                    if(pttl < 2_000){
                        jedis.expire(key, 4_000);
                        logger.info("add expire time for key : {}", key);
                    }
                }
            }, "expire1");
           // 设置为守护线程
           thread.setDaemon(true);
           thread.start();
           return true;
        }
        return false;
    }

    /**
     * 释放锁
     * @param key
     * @param value
     */
    public void unLock(String key, String value){
        Jedis jedis = jedisPool.getResource();
        String script =
                "if redis.call('get',KEYS[1]) == ARGV[1] then" +
                        "   return redis.call('del',KEYS[1]) " +
                        "else" +
                        "   return 0 " +
                        "end";
        jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));
    }
}

三、mian方法调用加锁解锁操作

public static void main(String[] args) {
        String key =  "lock2";
        String s = UUID.randomUUID().toString();
        RedisLock redisLock = new RedisLock();
        // 加锁
        redisLock.lock(key, s);
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            redisLock.unLock(key, s); // 释放锁
        }
    }

至此,分布式锁就实现了!

当然了,以上实现还不完善,没有实现可重入,我这里就不实现了,因为已经有了比较成熟的解决方案了,那就是Redisson

Redisson实现分布式锁传送门:https://blog.csdn.net/qq_43037478/article/details/109383965

Logo

鸿蒙生态一站式服务平台。

更多推荐