今天写 Redis 定时任务的时候,突然想到一个问题:当我定时任务在重置某个 key 的值的时候,而别的线程继续执行并且要获取这对 key-value 的时候,有没有可能获取回来的是 null?答案是不会的。
所以写了测试代码,大家一起来看看先。
// 每 20 秒执行 execut 方法,该方法主要是重置 key 的值。
@Scheduled(cron = "0/20 * * * * ?")
public void execut() throws Exception {
UUID id = UUID.randomUUID();
System.out.println("******create:" + id.toString() + "---time:" + new Date());
Thread.sleep(5000);
System.out.println("******sleep 5 second" + "---time:" + new Date());
RedisValueOps.setValue("test", id.toString());
System.out.println("******put:" + id.toString() + "---time:" + new Date());
}
// 每秒执行 execut2 方法,该方法主要是获取 key 的值。
@Scheduled(cron = "0/1 * * * * ?")
public void execut2() {
String value = (String) RedisValueOps.getValue("test");
System.out.println("======get:" + value + "---time:" + new Date());
}
下面是结果图
可以看到在 17分20秒 的时候生成了uuid,紧接着睡了 5 秒,再把 value put 到 redis。
然后紧跟着 execut2 方法就能获取到 value 值了。
我们再看 ======get: 的打印记录,在17分19秒执行了一次并获取到了 value 值,等再次获取到值的时候,是在17分25秒,中间有 5 秒钟的时间没有输出日志,说明是在堵塞中。
这个睡眠时间不够明显,我又让 execut 再睡 5 秒。
// 每 20 秒执行 execut 方法,该方法主要是重置 key 的值。
@Scheduled(cron = "0/20 * * * * ?")
public void execut() throws Exception {
UUID id = UUID.randomUUID();
System.out.println("******create:" + id.toString() + "---time:" + new Date());
Thread.sleep(5000);
System.out.println("******sleep 5 second" + "---time:" + new Date());
RedisValueOps.setValue("test", id.toString());
System.out.println("******put:" + id.toString() + "---time:" + new Date());
Thread.sleep(5000);
System.out.println("******sleep 5 second again" + "---time:" + new Date());
}
为什么上面说不明显呢?
因为第一张结果图把 value 值 put 进 redis 后,紧跟着就能 get 到 value 了,以为一 put ,另外的程序就能获取得到,所以我让 execut 再睡5秒。
当 value 被 put 到 redis 的时候,又继续睡了 5 秒,然而看 get 的输出日志,并没能获取到值,整个 execut 方法执行了 10 秒,而每秒执行的 execut2 却在外面堵塞了 10 秒。
由此猜测 redis 在读写的时候对这个 key 加锁了。
以下应该说一下原理的,由于知识有限,以后回来补充。