Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 分布式锁介绍
  • redis实现分布式锁缺陷
  • 可重入锁
    • 可重入锁原理
    • 流程图
    • 加锁LUA脚本
    • 释放锁LUA脚本
  • 锁重试
  • 锁超时
  • 主从一致性
  • 分布式锁
Nreal
2024-04-04
目录

可重入锁

# 可重入锁原理

  • ReentrantLock:记录当前为哪个线程,记录当前线程获取次数;

  • Redisson:使用hash数据结构,key为锁名称,value的k为线程标识,v为重入次数;

    tryLock多少次,就要unlock多少次;

    RLock lock = redissonClient.getLock("lock");
    void method1(){
        boolean isLock = lock.tryLock();
        if(!isLock){
            return ;
        }
        try{
            method2();
        }finally{
            lock.unlock();
        }
    }
    void method2(){
    	boolean isLock = lock.tryLock();
        if(!isLock){
            return ;
        }
        try{
            
        }finally{
            lock.unlock();
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

# 流程图

# 加锁LUA脚本

Local key = KEYS[1];--锁的key
local threadId = ARGV[1];--线程唯一标识
local releaseTime = ARGV[2];--锁的自动释放时间
-- 判断是否存在
if(redis.call('exists',key) == 0) then
    -- 不存在,获取锁
    redis.call('hset',key,threadId,'1');
    -- 设置有效期
    redis.call('expire',key,releaseTime);
    return 1;--返回结果
end
-- 锁已经存在,判断hreadId,是否是自己
if(redis.call('hexists',key,threadId) == 1) then
    -- 不存在,获取锁重入次数+1
    redis.call('hincrby',key,threadId,'1);
    -- 设置有效期
    redis.call('expire',key,releaseTime);
    return 1;-- 返回结果
end
return 0;-- 代码走到这里,说明获取锁的不是自己,获取锁失收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 释放锁LUA脚本

Local key KEYS[1];-- key
Local threadId = ARGV[1];-- 线程唯一标识
local releaseTime = ARGV[2];-- 锁的自动释放时间
-- 判断当前锁是否还是被自己持有
if (redis.call('HEXISTS',key,threadId) == 0) then
	return nil;-- 如果已经不是自己,则直接返回
end
-- 是自己的锁,则重入次数-1
Local count redis.call('HINCRBY',key,threadId,-1);
-- 判断是否重入次数是否已经为0
if (count 0) then
    -- 大于0说明不能释放锁,重置有效期然后返回
    redis.call('EXPIRE',key,releaseTime);
    return nil;
eLse -- 等于0说明可以释放锁,直接删除
    redis.call('DEL',key);
    return nil;
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
redis实现分布式锁缺陷
锁重试

← redis实现分布式锁缺陷 锁重试→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式