结果如下:

文章插图
可以看到,线程 A 先申请到锁,线程 B 后申请锁,结果线程 B 申请加锁失败 。
4.3 锁得可重入性实践当前线程加锁成功后,在线程执行中继续申请同一把锁,代码如下:
@Testpublic void redisLockReEntryTest() { String key = "test"; try { log.info("---申请加锁"); if (redisLock.lock(key, 10)) { // 模拟任务执行15秒 log.info("---加锁第一次成功"); if (redisLock.lock(key, 10)) { // 模拟任务执行15秒 log.info("---加锁第二次成功"); Thread.sleep(15000); log.info("---加锁第二次执行完毕"); } else { log.info("---加锁第二次失败"); } Thread.sleep(15000); log.info("---加锁第一次执行完毕"); } else { log.info("---加锁第一次失败"); } } catch (Exception e) { log.error(e.getMessage(), e); } finally { redisLock.unLock(key); }}结果如下:
文章插图
4.4 加锁逻辑讲解直接贴出本文最核心 RedisLock 类全部代码:
@Slf4j@Componentpublic class RedisLock { @Autowired public RedisTemplate redisTemplate; /** * 默认锁过期时间20秒 */ public static final Integer DEFAULT_TIME_OUT = 30; /** * 保存线程id-ThreadLocal */ private ThreadLocal<String> stringThreadLocal = new ThreadLocal<>(); /** * 保存定时任务(watch-dog)-ThreadLocal */ private ThreadLocal<ExecutorService> executorServiceThreadLocal = new ThreadLocal<>(); /** * 加锁,不指定过期时间 * * @param key key名称 * @return boolean */ public boolean lock(String key) { return lock(key, null); } /** * 加锁 * * @param key key名称 * @param timeout 过期时间 * @return boolean */ public boolean lock(String key, Integer timeout) { Integer timeoutTmp; if (timeout == null) { timeoutTmp = DEFAULT_TIME_OUT; } else { timeoutTmp = timeout; } String nanoId; if (stringThreadLocal.get() != null) { nanoId = stringThreadLocal.get(); } else { nanoId = IdUtil.nanoId(); stringThreadLocal.set(nanoId); } RedisScript<Long> redisScript = new DefaultRedisScript<>(buildLuaLockScript(), Long.class); Long execute = (Long) redisTemplate.execute(redisScript, Collections.singletonList(key), nanoId, timeoutTmp); boolean flag = execute != null && execute == 1; if (flag) { ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); executorServiceThreadLocal.set(scheduledExecutorService); scheduledExecutorService.scheduleWithFixedDelay(() -> { RedisScript<Long> renewRedisScript = new DefaultRedisScript<>(buildLuaRenewScript(), Long.class); Long result = (Long) redisTemplate.execute(renewRedisScript, Collections.singletonList(key), nanoId, timeoutTmp); if (result != null && result == 2) { ThreadUtil.shutdownAndAwAItTermination(scheduledExecutorService); } }, 0, timeoutTmp / 3, TimeUnit.SECONDS); } return flag; } /** * 释放锁 * * @param key key名称 * @return boolean */ public boolean unLock(final String key) { String nanoId = stringThreadLocal.get(); RedisScript<Long> redisScript = new DefaultRedisScript<>(buildLuaUnLockScript(), Long.class); Long execute = (Long) redisTemplate.execute(redisScript, Collections.singletonList(key), nanoId); boolean flag = execute != null && execute == 1; if (flag) { if (executorServiceThreadLocal.get() != null) { ThreadUtil.shutdownAndAwaitTermination(executorServiceThreadLocal.get()); } } return flag; } private String buildLuaLockScript() { return """ local key = KEYS[1] local value = ARGV[1] local time_out = ARGV[2] local result = redis.call('get', key) if result == value then return 1; end local lock_result = redis.call('setnx', key, value) if tonumber(lock_result) == 1 then redis.call('expire', key, time_out) return 1; else return 0; end """; } private String buildLuaUnLockScript() { return """ local key = KEYS[1] local value = ARGV[1] local result = redis.call('get', key) if result ~= value then return 0; else redis.call('del', key) end return 1; """; } private String buildLuaRenewScript() { return """ local key = KEYS[1] local value = ARGV[1] local timeout = ARGV[2] local result = redis.call('get', key) if result ~= value then return 2; end local ttl = redis.call('ttl', key) if tonumber(ttl) < tonumber(timeout) / 2 then redis.call('expire', key, timeout) return 1; else return 0; end """; }}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Redis 也支持全文搜索?这也太强了
- 聊聊分布式数据库TDSQL的技术架构
- pr怎么锁定图层,ps要怎么才可以锁定图层
- 华为手机触屏解锁怎么设置,华为解锁直接进入桌面怎么设置
- 刘德华11岁女儿时隔5年露面!眉头深锁送别爷爷,长得与妈妈极像
- 解锁 C++ 并发编程的钥匙:探索 Atomic 变量
- MySQL:逃不掉的锁事,间隙锁
- 宋祖英终于换对新发型,56岁嫩回36岁,锁骨短发配粉衣少女感十足
- 栖桐国际:面霜可以锁住皮肤表面,形成一个保护层,防止水分流失
- TVB女星自曝被赶出家门!密码锁被改衣服被扔掉,新婚4个月
