文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

redis中RedissonLock如何实现等待锁的

2024-04-02 19:55

关注

前言

经常会有到这样的需求,就是在一个查询接口,第一次查询的时候,如果没有查询到就要执行初始化方法,初始化数据出来,之后的查询就可以直接查询库里的数据了。这样设计的目的是,如果需要初始化的数据特别大,无法再一次调用方法里处理完,或者说数据并不是每条都需要初始化,这种情况下,优先查询的数据优先初始化。

问题

这种方案随之而来就会引发一个问题。查询接口众所周知是个自然幂等的,不需要我们额外去做幂等处理。但是在方案中,这个查询就不单单是个查询了。没有查询到就要执行初始化方法,本质上是个插入逻辑。这就需要我们自己去做幂等了。

方案

单台服务,我们可以用Java的锁来实现幂等,每条数据的主键id来当锁。但在现在基本上都是分布式服务,如同上篇文章说的,我们可以用分布式锁RedissonLock来实现。
并发第一次请求时,竞争RedissonLock,谁获得了锁,谁就执行初始化方法,没有竞争到锁的请求,可以设置一个等待时间,等待锁释放。锁释放了,就可以先查询数据有没有初始化好,完成了就直接查库。这里,就要提一下RedissonLock是如何实现等待的?

tryLock

RedissonLock在加锁方法提供了一个api,提供了一个参数waitTime即等待时间。


public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit)

在waitTime时间内会订阅消息,这里用的是redis本身的发布订阅功能。


RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {
    if (!subscribeFuture.cancel(false)) {
        subscribeFuture.onComplete((res, e) -> {
            if (e == null) {
                unsubscribe(subscribeFuture, threadId);
            }
        });
    }
    acquireFailed(threadId);
    return false;
}

这样,在释放锁的时候,同时发布消息出来。所有监听该锁的线程都将收到通知,那么,这些线程将再次去竞争加锁,从而达到我们需要的幂等功能。我们在看看释放锁的逻辑,是不是发布消息了?

unlockInnerAsync


protected RFuture<Boolean> unlockInnerAsync(long threadId) {
    return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
            "if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
                "return nil;" +
            "end; " +
            "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
            "if (counter > 0) then " +
                "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                "return 0; " +
            "else " +
                "redis.call('del', KEYS[1]); " +
                "redis.call('publish', KEYS[2], ARGV[1]); " +
                "return 1; "+
            "end; " +
            "return nil;",
            Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));

}

可以看出在unlockInnerAsync方法里,执行了lua脚本,在脚本里,我们很容易能看到执行了publish命令。

思考

Redisson巧妙的用了redis的发布订阅功能,实现了分布式锁的等待功能。那么我们在实际业务应用中,redis的发布订阅功能还有哪些使用场景呢?欢迎留言讨论!

到此这篇关于redis中RedissonLock如何实现等待锁的的文章就介绍到这了,更多相关RedissonLock 等待锁内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯