最新Redis分布式锁,看完不懂你打我(1),2024一位Java中级程序员的跳槽面经

最后我们该如何学习?

1、看视频进行系统学习

这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。

另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

2、读源码,看实战笔记,学习大神思路

“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。

Spring源码深度解析:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Mybatis 3源码深度解析:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Redis学习笔记:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Spring Boot核心技术-笔记:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

3、面试前夕,刷题冲刺

面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。

关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。

人生短暂,别稀里糊涂的活一辈子,不要将就。

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

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

解锁流程:

Redission加锁使用的是redis的hash结构。

  • key :要锁的资源名称

  • filed :uuid+“:”+线程id

  • value : 数值型,可以实现可重入锁

源码里面用到了netty里面Promise的一些api,我列出来帮助理解:

// 异步操作完成且正常终止

boolean isSuccess();

// 异步操作是否可以取消

boolean isCancellable();

// 异步操作失败的原因

Throwable cause();

// 添加一个监听者,异步操作完成时回调,类比javascript的回调函数

Future addListener(GenericFutureListener<? extends Future<? super V>> listener);

Future removeListener(GenericFutureListener<? extends Future<? super V>> listener);

// 阻塞直到异步操作完成

Future await() throws InterruptedException;

// 同上,但异步操作失败时抛出异常

Future sync() throws InterruptedException;

// 非阻塞地返回异步结果,如果尚未完成返回null

V getNow();

源码分析:

加锁:

public RLock getLock(String name) {

return new RedissonLock(connectionManager.getCommandExecutor(), name);

}

public RedissonLock(CommandAsyncExecutor commandExecutor, String name) {

super(commandExecutor, name);

//命令执行器

this.commandExecutor = commandExecutor;

//uuid

this.id = commandExecutor.getConnectionManager().getId();

//超时时间,默认30s

this.internalLockLeaseTime = commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout();

this.entryName = id + “:” + name;

}

public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {

//获取线程id

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

//尝试获取锁

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

// lock acquired

//ttl为空则代表加锁成功

if (ttl == null) {

return;

}

//如果获取锁失败,则订阅到对应这个锁的channel,等其他线程释放锁时,通知线程去获取锁

RFuture future = subscribe(threadId);

commandExecutor.syncSubscription(future);

try {

while (true) {

//再次尝试获取锁

ttl = tryAcquire(leaseTime, unit, threadId);

// lock acquired

if (ttl == null) {

break;

}

// waiting for message

//ttl大于0,则等待ttl时间后继续尝试获取锁

if (ttl >= 0) {

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

} else {

getEntry(threadId).getLatch().acquire();

}

}

} finally {

//取消对channel的订阅

unsubscribe(future, threadId);

}

// get(lockAsync(leaseTime, unit));

}

再来看看里面的尝试获取锁的代码:

private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {

return get(tryAcquireAsync(leaseTime, unit, threadId));

}

private RFuture tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {

if (leaseTime != -1) {

//如果带有过期时间,则按照普通方式获取锁

return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);

}

//先按照30秒的过期时间来执行获取锁的方法

RFuture ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);

//异步执行回调监听

ttlRemainingFuture.addListener(new FutureListener() {

@Override

//如果还持有这个锁,则开启定时任务不断刷新该锁的过期时间

public void operationComplete(Future future) throws Exception {

//没有成功执行完成

if (!future.isSuccess()) {

return;

}

//非阻塞地返回异步结果,如果尚未完成返回null

Long ttlRemaining = future.getNow();

// lock acquired

if (ttlRemaining == null) {

scheduleExpirationRenewal(threadId);

}

}

});

return ttlRemainingFuture;

}

看门狗逻辑:

使用的是Netty的Timeout延迟任务做的。

  • 比如锁过期 30 秒, 每过 1/3 时间也就是 10 秒会检查锁是否存在, 存在则更新锁的超时时间

加锁脚本

RFuture tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand command) {

internalLockLeaseTime = unit.toMillis(leaseTime);

return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,

//如果锁不存在,则通过hset设置它的值,并设置过期时间

"if (redis.call(‘exists’, KEYS[1]) == 0) then " +

"redis.call(‘hset’, KEYS[1], ARGV[2], 1); " +

"redis.call(‘pexpire’, KEYS[1], ARGV[1]); " +

"return nil; " +

"end; " +

//如果锁已存在,并且锁的是当前线程,则通过hincrby给数值递增1,并重新设置过期时间

"if (redis.call(‘hexists’, KEYS[1], ARGV[2]) == 1) then " +

"redis.call(‘hincrby’, KEYS[1], ARGV[2], 1); " +

"redis.call(‘pexpire’, KEYS[1], ARGV[1]); " +

"return nil; " +

"end; " +

//如果锁已存在,但并非本线程,则返回过期时间

“return redis.call(‘pttl’, KEYS[1]);”,

Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));

最后

Java架构进阶面试及知识点文档笔记

这份文档共498页,其中包括Java集合,并发编程,JVM,Dubbo,Redis,Spring全家桶,MySQL,Kafka等面试解析及知识点整理

image

Java分布式高级面试问题解析文档

其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!

image

互联网Java程序员面试必备问题解析及文档学习笔记

image

Java架构进阶视频解析合集

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

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

,分库分表,微服务架构,分布式高可用,读写分离等等!

[外链图片转存中…(img-Wv5T9KbC-1715646953138)]

互联网Java程序员面试必备问题解析及文档学习笔记

[外链图片转存中…(img-hfaj2blT-1715646953139)]

Java架构进阶视频解析合集

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

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

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值