分布式锁(设置锁和过期时间)

问题描述:

随着业务发展的需要,原单体单机部署的系统被演化分成分布式集群系统后,由于分布式系统多线程、多进程且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题

分布式锁主流的实现方案:

1、基于数据库实现分布式锁

2、基于缓存(Redis等)

3、基于Zookeeper

每一种分布式锁解决方案都有各自的优缺点。

解决方案:基于Redis实现分布式锁

redis:命令

# set sku:1:info "OK" NX PX 10000

EX second:设置键的过期时间为seconds秒,SET key value EX second效果等同于SETEX key second value

NX::只在键不存在时,才对键进行设置操作,SET key value NX效果等同于SETNX key value

XX:只在键已经存在时,才对键进行设置操作

DEL:释放锁

设置过期时间解决锁一直不能释放的问题

上锁之后出现异常无法设置过期时间:上锁时同时设置过期时间 set users 10 nx ex 10   既上锁又设置过期时间同步进行。

复制代码
 @GetMapping("/testLock")
    public void testLock(){
        //1、获取锁, setnx
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111", 3, TimeUnit.SECONDS);
        //2、获取锁成功,查询num的值
        if(lock){
            Object value = redisTemplate.opsForValue().get("num");
            //2.1 判断num为空return
            if(StringUtils.isEmpty(value)){
                return;
            }
            //2.2 有值就转成int
            int num = Integer.parseInt(value + "");
            //2。3 把redis的num加1
            redisTemplate.opsForValue().set("num", ++num);
            //2.4 释放锁,del
            redisTemplate.delete("lock");
        }else {
            //3 获取锁失败,每个0.1秒再获取
            try{
                Thread.sleep(100);
                testLock();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
复制代码

存在问题:误删,锁释放错了

a:先操作

1、上锁

2、具体操作

服务器卡顿

3、锁自动释放

b:抢到锁,具体操作

a服务器反应过来,进行操作,手动释放锁,释放了b的锁

方法:使用UUID表示不同操作

1、set lock uuid nx ex 10

2、释放锁时,首先判断当前uuid和要释放锁的uuid是否一样。

复制代码
 @GetMapping("/testLock")
    public void testLock(){
        String uuid = UUID.randomUUID().toString();
        //1、获取锁, setnx
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
        //2、获取锁成功,查询num的值
        if(lock){
            Object value = redisTemplate.opsForValue().get("num");
            //2.1 判断num为空return
            if(StringUtils.isEmpty(value)){
                return;
            }
            //2.2 有值就转成int
            int num = Integer.parseInt(value + "");
            //2。3 把redis的num加1
            redisTemplate.opsForValue().set("num", ++num);
            //2.4 释放锁,del、判断比较uuid是否一样
            if(redisTemplate.opsForValue().get("lock").equals(uuid)){
                redisTemplate.delete("lock");
            }
            
        }else {
            //3 获取锁失败,每个0.1秒再获取
            try{
                Thread.sleep(100);
                testLock();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
复制代码

 

posted @   佛系粥米  阅读(379)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示