分布式锁的实现

前言:
分布式技术提升了系统的运行效率,但是也产生了新的问题(如分布式锁、全局唯一序列等)
这些问题不能直接用Java原生的技术解决,但在分布式系统中却不可或缺
Distributor基于Redis实现常用的分布式组件(如分布式锁、分布式序列、分布式限流等),简单、可靠、开箱即用

实现Redis的分布式锁主要通过lua脚本,既简单又安全
完整项目地址 https://gitee.com/HappyChicken/Distributor 麻烦大家顺手给个Star~

这里给出分布式锁的核心代码段供参考:

  1. 提前定义好Redis命令中需要的字符串以及默认过期时间
    // Redis命令常用字符串
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    // 默认锁过期时间 10s
    private int lockTimeout = 10000;
    // 重试时间 0.5s
    private int retryAwait = 500;
  1. 加锁(本质是在Redis中设置一个有过期时间的Key,如果加锁成功会返回这个Key对应的value,
    用于解锁)
    // 尝试加锁,可以指定尝试时间
    @Override
    public String tryLock(long tryLockTime, TimeUnit timeUnit) {
        // 是否死循环获取锁
        boolean forever = tryLockTime < 0;
        // 开始获取锁的时间
        final long startMillis = System.currentTimeMillis();
        // 转为秒
        final Long millisToWait = (timeUnit != null) ? timeUnit.toMillis(tryLockTime) : 0;

        String lockSuccess = null;
        // 如果没有加锁成功,循环尝试获取锁
        while (lockSuccess == null) {
            lockSuccess = doLock();
            // 获取成功 退出
            if (lockSuccess != null) {
                break;
            }
            // 如果超过了获取锁的最长时间,退出
            if (!forever && System.currentTimeMillis() - startMillis - retryAwait > millisToWait) {
                break;
            }
            // 睡眠重试时间,避免太频繁的重试
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(retryAwait));
        }
        return lockSuccess;
    }
    private String doLock() {
    	// value值是一个随机UUID
        String lockId = IdUtils.getUUID("");
        Jedis jedis = null;
        try {
            // 获得jedis连接
            jedis = getJedis();
            // 尝试加锁,如果成功返回OK
            // 5个参数:key  value  (NX)key不存在才设置  (PX)设置过期时间  过期时间
            String result = getJedis().set(getKey(), lockId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME
                    lockTimeout);
            // 加锁成功返回value值,用于解锁
            return LOCK_SUCCESS.equals(result) ? lockId : null;
        } finally {
             //关闭连接
             jedis.close();
        }
    }
  1. 解锁(传入加锁成功返回的lockId进行解锁,关键在于lua脚本的编写)
    public void unLock(String lockId) {
        // 如果get key的值和预期一样 就删除该key,保证由加锁的人来解锁
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                "then return redis.call('del', KEYS[1]) else return -1 end";
        Jedis jedis = null;
        try {
        	// 获得连接
            jedis = getJedis();
            // 执行lua脚本
            jedis.eval(luaScript,
                    Collections.singletonList(getKey()), Collections.singletonList(lockId));
        } finally {
            // 关闭资源
            jedis.close();
        }
    }

更多详情可以到 https://gitee.com/HappyChicken/Distributor 中查看!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值