Redis——构建可重入分布式锁

文章介绍了如何在Redis中实现可重入分布式锁,通过使用Java的ThreadLocal存储每个线程持有锁的计数,确保同一线程可以多次加锁。示例代码展示了如何封装Jedis的set方法以支持可重入,并提供了lock和unlock方法的实现。
摘要由CSDN通过智能技术生成

可重入性

可重入性是指线程在持有锁的情况下再次请求加锁,如果一个锁支持同一个线程的多次加锁,那么这个锁就是可重入的。比如 Java 语言里有个 ReentrantLock 就是可重入锁。

Redis 分布式锁如果要支持可重入,需要对客户端的 set 方法进行包装,使用线程的 Threadlocal 变量 存储当前持有锁的计数。

示例

package com.example.demo.book;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author: acton_zhang
 * @Date: 2023/4/15 11:28 下午
 * @Version 1.0
 * Redis可重入分布式锁
 */
public class RedisWithReentrantLock {
    //使用线程的Threadlocal存储当前持有锁的计数
    private ThreadLocal<Map> lockers = new ThreadLocal<>();
    private Jedis jedis;

    public RedisWithReentrantLock(Jedis jedis) {
        this.jedis = jedis;
    }

    private boolean _lock(String key, String value, long ttl) {
        SetParams params = new SetParams();
        //使用:set key value ex ttl nx 命令。一般来说,超时时间ttl要大于业务时间
        params.nx().ex(ttl);
        return jedis.set(key, value, params) != null;
    }

    private void _unlock(String key) {
        jedis.del(key);
    }

    private Map<String, Integer> currentLockers() {
        Map<String, Integer> refs = lockers.get();
        if (refs != null) {
            return refs;
        }
        lockers.set(new HashMap());
        return lockers.get();
    }

    //获取锁
    public boolean lock(String key, String value, long ttl) {
        Map<String, Integer> refs = currentLockers();
        Integer refCnt = refs.get(key);
        if (refCnt != null) {
            refs.put(key, refCnt + 1);
            return true;
        }
        boolean ok = this._lock(key, value, ttl);
        if (!ok) {
            return false;
        }
        refs.put(key, 1);
        return true;
    }

    //释放锁
    public boolean unlock(String key) {
        Map<String, Integer> refs = currentLockers();
        Integer refCnt = refs.get(key);
        if (refCnt == null) {
            return false;
        }
        refCnt -= 1;
        if (refCnt > 0) {
            refs.put(key, refCnt);
        } else {
            refs.remove(key);
            this._unlock(key);
        }
        return true;
    }

    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.auth("123456");
        RedisWithReentrantLock rlock = new RedisWithReentrantLock(jedis);
        System.out.println(rlock.lock("testlock", "value", 5l));
        System.out.println(rlock.lock("testlock", "value", 5l));
        System.out.println(rlock.unlock("testlock"));
        System.out.println(rlock.unlock("testlock"));
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值