先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
可以看出,当把key为lock的值设置为"Java"后,再设置成别的值就会失败,看上去很简单,也好像独占了锁,但有个致命的问题,就是key没有过期时间,这样一来,除非手动删除 key 或者获取锁后设置过期时间,不然其他线程永远拿不到锁。
既然这样,我们给 key 加个过期时间总可以吧,直接让线程获取锁的时候执行两步操作:
SETNX Key 1
EXPIRE Key Seconds
这个方案也有问题,因为获取锁和设置过期时间分成两步了,不是原子性操作,有可能获取锁成功但设置时间失败,那样不就白干了吗。
不过也不用急,这种事情 Redis 官方早为我们考虑到了,所以就引出了下面这个命令
2、SETEX,用法SETEX key seconds value
将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在,SETEX 命令将覆写旧值。
这个命令类似于以下两个命令:
SET key value
EXPIRE key seconds # 设置生存时间
这两步动作是原子性的,会在同一时间完成。
3、PSETEX ,用法PSETEX key milliseconds value
这个命令和SETEX命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像SETEX命令那样,以秒为单位。
不过,从 Redis 2.6.12 版本开始,SET命令可以通过参数来实现和SETNX、SETEX、PSETEX 三个命令的效果。
就比如这条命令
SET key value NX EX seconds
加上 NX、EX 参数后,效果就相当于 SETEX,这也是 Redis 获取锁写法里面最常见的。
怎么释放锁
=====
释放锁的命令就简单了,直接删除 key 就行,但我们前面说了,因为分布式锁必须由锁的持有者自己释放,所以我们必须先确保当前释放锁的线程是持有者,没问题了再删除,这样一来,就变成两个步骤了,似乎又违背了原子性了,怎么办呢?
不慌,我们可以用 lua 脚本把两步操作做拼装,就好像这样:
if Redis.call(“get”,KEYS[1]) == ARGV[1]
then
return Redis.call(“del”,KEYS[1])
else
return 0
end
KEYS[1]是当前 key 的名称,ARGV[1]可以是当前线程的 ID(或者其他不固定的值,能识别所属线程即可),这样就可以防止持有过期锁的线程,或者其他线程误删现有锁的情况出现。
代码实现
====
知道了原理后,我们就可以手写代码来实现 Redis 分布式锁的功能了,因为本文的目的主要是为了讲解原理,不是为了教大家怎么写分布式锁,所以我就用伪代码实现了。
首先是 Redis 锁的工具类,包含了加锁和解锁的基础方法:
public class RedisLockUtil {
private String LOCK_KEY = “redis_lock”;
// key的持有时间,5ms
private long EXPIRE_TIME = 5;
// 等待超时时间,1s
private long TIME_OUT = 1000;
// Redis命令参数,相当于nx和px的命令合集
private SetParams params = SetParams.setParams().nx().px(EXPIRE_TIME);
// Redis连接池,连的是本地的Redis客户端
JedisPool jedisPool = new JedisPool(“127.0.0.1”, 6379);
/**
* 加锁
* @param id
* 线程的id,或者其他可识别当前线程且不重复的字段
* @return
*/
public boolean lock(String id) {
Long start = System.currentTimeMillis();
Jedis jedis = jedisPool.getResource();
try {
for (;😉 {
// SET命令返回OK ,则证明获取锁成功
String lock = jedis.set(LOCK_KEY, id, params);
if (“OK”.equals(lock)) {
return true;
}
// 否则循环等待,在TIME_OUT时间内仍未获取到锁,则获取失败
long l = System.currentTimeMillis() - start;
if (l >= TIME_OUT) {
return false;
}
try {
// 休眠一会,不然反复执行循环会一直失败
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
jedis.close();
}
}
/**
* 解锁
* @param id
* 线程的id,或者其他可识别当前线程且不重复的字段
* @return
*/
public boolean unlock(String id) {
Jedis jedis = jedisPool.getResource();
// 删除key的lua脚本
String script = “if Redis.call(‘get’,KEYS[1]) == ARGV[1] then” + " return Redis.call(‘del’,KEYS[1]) " + “else”
+ " return 0 " + “end”;
try {
String result =
jedis.eval(script, Collections.singletonList(LOCK_KEY), Collections.singletonList(id)).toString();
return “1”.equals(result);
} finally {
jedis.close();
}
}
}
具体的代码作用注释已经写得很清楚了,然后我们就可以写一个 demo 类来测试一下效果:
public class RedisLockTest {
private static RedisLockUtil demo = new RedisLockUtil();
private static Integer NUM = 101;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
String id = Thread.currentThread().getId() + “”;
boolean isLock = demo.lock(id);
try {
// 拿到锁的话,就对共享参数减一
if (isLock) {
NUM–;
System.out.println(NUM);
}
} finally {
// 释放锁一定要注意放在finally
总结:绘上一张Kakfa架构思维大纲脑图(xmind)
其实关于Kafka,能问的问题实在是太多了,扒了几天,最终筛选出44问:基础篇17问、进阶篇15问、高级篇12问,个个直戳痛点,不知道如果你不着急看答案,又能答出几个呢?
若是对Kafka的知识还回忆不起来,不妨先看我手绘的知识总结脑图(xmind不能上传,文章里用的是图片版)进行整体架构的梳理
梳理了知识,刷完了面试,如若你还想进一步的深入学习解读kafka以及源码,那么接下来的这份《手写“kafka”》将会是个不错的选择。
-
Kafka入门
-
为什么选择Kafka
-
Kafka的安装、管理和配置
-
Kafka的集群
-
第一个Kafka程序
-
Kafka的生产者
-
Kafka的消费者
-
深入理解Kafka
-
可靠的数据传递
-
Spring和Kafka的整合
-
SpringBoot和Kafka的整合
-
Kafka实战之削峰填谷
-
数据管道和流式处理(了解即可)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Boot和Kafka的整合
-
Kafka实战之削峰填谷
-
数据管道和流式处理(了解即可)
[外链图片转存中…(img-yxOfLhlI-1713362268589)]
[外链图片转存中…(img-xZDGMyNY-1713362268590)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-MaEBxHHK-1713362268590)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!