最新面试官:Redis 分布式锁如何自动续期,腾讯大牛教你自己写Java框架

最后

面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?

掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • LockTime设置过大,万一服务出现异常无法正常释放锁,那么出现这种异常锁的时间也就越长。

我们只能通过经验去配置,一个可以接受的值,基本上是这个服务历史上的平均耗时再增加一定的buff。总体来说,设置一个合理的过期时间并不容易

我们也可以不设置过期时间,让业务运行结束后解锁,但是如果客户端出现了异常结束了或宕机了,那么这个锁就无法解锁,变成死锁;

3、自动续期


我们可以先给锁设置一个LockTime,然后启动一个守护线程,让守护线程在一段时间后,重新去设置这个锁的LockTime。

看起来很简单,但实现起来并不容易。

  • 和释放锁的情况一样,我们需要先判断持有锁客户端是否有变化。否则会造成无论谁持有锁,守护线程都会去重新设置锁的LockTime。

  • 守护线程要在合理的时间再去重新设置锁的LockTime,否则会造成资源的浪费。不能动不动就去续。

  • 如果持有锁的线程已经处理完业务了,那么守护线程也应该被销毁。不能业务运行结束了,守护者还在那里继续运行,浪费资源。

另外,关注公号“终码一生”,回复关键词“资料”,获取视频教程和最新的面试资料!

4、看门狗


Redisson的看门狗机制就是这种机制实现自动续期的

图片

Redissson tryLock

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {

long time = unit.toMillis(waitTime);

long current = System.currentTimeMillis();

long threadId = Thread.currentThread().getId();

// 1.尝试获取锁

Long ttl = tryAcquire(leaseTime, unit, threadId);

// lock acquired

if (ttl == null) {

return true;

}

// 申请锁的耗时如果大于等于最大等待时间,则申请锁失败.

time -= System.currentTimeMillis() - current;

if (time <= 0) {

acquireFailed(threadId);

return false;

}

current = System.currentTimeMillis();

/**

  • 2.订阅锁释放事件,并通过 await 方法阻塞等待锁释放,有效的解决了无效的锁申请浪费资源的问题:

  • 基于信息量,当锁被其它资源占用时,当前线程通过 Redis 的 channel 订阅锁的释放事件,一旦锁释放会发消息通知待等待的线程进行竞争.

  • 当 this.await 返回 false,说明等待时间已经超出获取锁最大等待时间,取消订阅并返回获取锁失败.

  • 当 this.await 返回 true,进入循环尝试获取锁.

*/

RFuture subscribeFuture = subscribe(threadId);

// await 方法内部是用 CountDownLatch 来实现阻塞,获取 subscribe 异步执行的结果(应用了 Netty 的 Future)

if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {

if (!subscribeFuture.cancel(false)) {

subscribeFuture.onComplete((res, e) -> {

if (e == null) {

unsubscribe(subscribeFuture, threadId);

}

});

}

acquireFailed(threadId);

return false;

}

try {

// 计算获取锁的总耗时,如果大于等于最大等待时间,则获取锁失败.

time -= System.currentTimeMillis() - current;

if (time <= 0) {

acquireFailed(threadId);

return false;

}

/**

  • 3.收到锁释放的信号后,在最大等待时间之内,循环一次接着一次的尝试获取锁

  • 获取锁成功,则立马返回 true,

  • 若在最大等待时间之内还没获取到锁,则认为获取锁失败,返回 false 结束循环

*/

while (true) {

long currentTime = System.currentTimeMillis();

// 再次尝试获取锁

ttl = tryAcquire(leaseTime, unit, threadId);

// lock acquired

if (ttl == null) {

return true;

}

// 超过最大等待时间则返回 false 结束循环,获取锁失败

time -= System.currentTimeMillis() - currentTime;

if (time <= 0) {

acquireFailed(threadId);

return false;

}

/**

  • 6.阻塞等待锁(通过信号量(共享锁)阻塞,等待解锁消息):

*/

currentTime = System.currentTimeMillis();

if (ttl >= 0 && ttl < time) {

//如果剩余时间(ttl)小于wait time ,就在 ttl 时间内,从Entry的信号量获取一个许可(除非被中断或者一直没有可用的许可)。

getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);

} else {

//则就在wait time 时间范围内等待可以通过信号量

getEntry(threadId).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);

}

// 更新剩余的等待时间(最大等待时间-已经消耗的阻塞时间)

time -= System.currentTimeMillis() - currentTime;

if (time <= 0) {

acquireFailed(threadId);

return false;

}

}

} finally {

// 7.无论是否获得锁,都要取消订阅解锁消息

unsubscribe(subscribeFuture, threadId);

}

return get(tryLockAsync(waitTime, leaseTime, unit));

}

  • 尝试获取锁,返回 null 则说明加锁成功,返回一个数值,则说明已经存在该锁,ttl 为锁的剩余存活时间。

  • 如果此时客户端 2 进程获取锁失败,那么使用客户端 2 的线程 id(其实本质上就是进程 id)通过 Redis 的 channel 订阅锁释放的事件。如果等待的过程中一直未等到锁的释放事件通知,当超过最大等待时间则获取锁失败,返回 false,也就是第 39 行代码。如果等到了锁的释放事件的通知,则开始进入一个不断重试获取锁的循环。

最后

最后,强调几点:

  • 1. 一定要谨慎对待写在简历上的东西,一定要对简历上的东西非常熟悉。因为一般情况下,面试官都是会根据你的简历来问的; 能有一个上得了台面的项目也非常重要,这很可能是面试官会大量发问的地方,所以在面试之前好好回顾一下自己所做的项目;
  • 2. 和面试官聊基础知识比如设计模式的使用、多线程的使用等等,可以结合具体的项目场景或者是自己在平时是如何使用的;
  • 3. 注意自己开源的Github项目,面试官可能会挖你的Github项目提问;

我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!

以上面试专题的答小编案整理成面试文档了,文档里有答案详解,以及其他一些大厂面试题目。

面试答案

三面头条+四面阿里+五面腾讯拿offer分享面经总结,最终入职阿里

三面头条+四面阿里+五面腾讯拿offer分享面经总结,最终入职阿里

三面头条+四面阿里+五面腾讯拿offer分享面经总结,最终入职阿里

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

[外链图片转存中…(img-gcRsDeAR-1715686088955)]

[外链图片转存中…(img-k6qnP5Jf-1715686088955)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis分布式锁可以通过设置一个过期时间来防止死锁的发生,同时还可以自动续期。在Redisson实现分布式锁的代码中,可以看到设置了一个扫描间隔参数`setScanInterval`,这个参数表示每隔一定时间就会来确认一次锁是否释放。如果锁没有释放,那么就会自动续期,保证锁的有效性。 在具体的代码实现中,使用了Redisson的RLock对象来获取锁,并使用`lock.lock()`来加锁,`lock.unlock()`来释放锁。当执行`lock.lock()`时,会将锁的状态存储到Redis中,并设置一个过期时间。在锁的过期时间内,Redisson会定期发送续期请求来更新锁的过期时间,确保锁的持有者能够在业务处理完成前一直持有锁。一旦业务处理完成,调用`lock.unlock()`来释放锁时,Redisson会在Redis中删除对应的锁信息,从而释放锁。 关于Redis分布式锁的更多详细信息,你可以参考Redisson的官方文档,链接为:https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis分布式锁如何自动续期](https://blog.csdn.net/upstream480/article/details/121578638)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatgptT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [06-Redis 实现分布式锁和解决锁续期问题](https://blog.csdn.net/jack1liu/article/details/96270927)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatgptT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值