一、背景

如果某个客户端获得锁之后处理时间超过最大约定时间,或者持锁期间内发生了故障导致无法主动释放锁,其持有的锁也能够被其他机制正确释放,并保证后续其它客户端也能加锁,整个处理流程继续正常执行。

简单解释一下:

  1. 客户端抢到分布式锁之后开始执行任务,执行完毕后再释放分布式锁。
  2. 持锁后因客户端异常未能把锁释放,会导致锁成为永恒锁。
  3. 为了避免这种情况,在创建锁的时候给锁指定一个过期时间。
  4. 到期之后锁会被自动删除掉,这个角度看是对锁资源的一种保护。

二、理还乱?

逻辑看很简单,也很清晰,但任何事情都有两面性,自动删除自然有理,但肯定也有弊端。如果要把锁的功能做的健壮,总要从不断地自我质疑、自我反思中,理顺思路,寻找答案,我认为这属于自省式学习,以后也想尝试这种模式,一起来试试吧:

  • 问题:锁过期了会被删掉,可是任务没结束怎么办?

    如果锁被释放的时候,任务尚未执行完毕,那就可能导致其它客户端又抢到锁,任务被重复执行。

  • 问题:把锁的过期时间定的长一点?

    逻辑听起来没错,如果你能确定任务的最大耗时,那没问题;大部分情况都很难确定任务的最大耗时该是多少。

  • 问题:锁的过期时间定多长合适?

    反正会被释放,过期时间定的足够长吧;如果锁使用的频率很高,加了锁程序有bug释放不掉,服务端岂不是要出现大量的垃圾数据?思来想去,对一个健壮的分布式锁来说,过期时间设置太长了不合适,设置太短了也不合适。

  • 问题:怎么平衡?

    不长不短,主动延期!持锁期间,酌情推后锁的过期时间,以基于Redis的分布式锁来说,就需要调用 API 重置锁 key 的过期时间。当前线程持锁后在执行任务期间不能再调用 API 重试锁 key 的过期时间。

  • 问题:谁来调用API呢?

    需要使用其他的线程来执行续期。

  • 问题:给每个锁配一个线程?

    可以,如果使用分布式锁的场景中没有什么并发,一个客户端也就那么三两个锁同时存在,那就没问题。每个锁抢锁成功后,开启一个线程,在线程中通过循环给锁续期。

    public void run() {while (true) {// 续租action.run();}
    }
    复制代码
  • 问题:多久执行一次续期?

    有一些常规处理是续租间隔默认采用过期时间的1/3。若把锁的过期时间设定为与实际耗时相差不大,这样通过一两次续租基本就满足了大部分的情况。

  • 问题:为什么要触发一次续期操作呢,这不浪费资源吗?

    采用过期时间1/3间隔,若用户定义锁3秒过期,那每秒钟都有一个续期指令,有没有觉得也不太合适。

  • 问题:要不要避免续期指令太频繁?

    避免续期指令太频繁调用是有必要的,也可以增加一个续期的最小间隔时间,比如最少是5秒。可由用户自己控制续期周期,没必要一定要发起续期调用。比如任务执行大多在5秒钟,那么就把锁定为7秒,续期时间定在6秒,那么6秒内任务结束了就不用续期,即不必把过期时间定的太长,也不必执行一两次续期操作。

  • 问题:续租的间隔怎么实现?

    线程内间隔控制通常是通过 sleep() 方法,稍微精准一点的话,单位使用毫秒。

    public void run() {while (true) {// 1、间隔TimeUnit.MILLISECONDS.sleep(sleepTime);// 2、续租action.run();}
    }
    复制代码
  • 问题:线程要关闭吧?

    释放锁的时候要主动关闭负责续期的线程,所以线程的循环里要有一个变量来控制退出 while 循环

    public void run() {while (isRunning) {// 1、间隔TimeUnit.MILLISECONDS.sleep(sleepTime);// 2、续租action.run();}
    }
    复制代码
  • 问题:变量是跨线程访问,如何保证跨线程的可见性呢?

    在变量上增加 volatile 关键字。

    private volatile boolean isRunning = true;void cancel(){//控制线程退出this.isRunning = true;
    }
    复制代码
  • 问题:如果续期线程里在 sleep(),那就一直等 sleep() 结束?

    如果等到 sleep() 结束,就挺浪费资源的

  • 问题:能不能快速结束 sleep() 状态?

    可以,通过 interrupt(),需留意,被打断的时候会抛异常 InterruptedException

    void cancel(){//控制线程退出this.isRunning = true;//中断线程this.interrupt();
    }
    复制代码

到这里,似乎都理顺了。


三、新的思考

  • 问题:如果同时有成百上千个锁呢?

    同时有成百上千个线程在工作,你若认为没问题,不存在,那ok,不用继续看下一篇。

  • 那怎么办呢?

    可以用 Executors.newScheduledThreadPool ,里边有 scheduleAtFixedRate

  • 阿里 Java 代码规范不允许用Execurots嘛?

  • 不能用?风险是什么?你没看累嘛?


累了吧,下一篇再聊,休息休息。

四、最后说一句

我是石页兄,如果这篇文章对您有帮助,或者有所启发的话,欢迎关注笔者的微信公众号【 架构染色 】进行交流和学习。您的支持是我坚持写作最大的动力

分布式锁主动续期的入门级实现-自省 | 简约而不简单相关推荐

  1. 简约而不简单!分布式锁入门级实现主动续期-自省

    一.背景 一个分布式锁应具备的功能特点中有避免死锁这一条: 如果某个客户端获得锁之后处理时间超过最大约定时间,或者持锁期间内发生了故障导致无法主动释放锁,其持有的锁也能够被其他机制正确释放,并保证后续 ...

  2. 面试官问我,Redis分布式锁如何续期?懵了。

    作者:肥朝,来自:肥朝(ID:feichao_java) 前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的老粉丝 ...

  3. Redis分布式锁的原理以及如何续期

    面试问题 Redis锁的过期时间小于业务的执行时间该如何续期? 问题分析 首先如果你之前用Redis的分布式锁的姿势正确,并且看过相应的官方文档的话,这个问题So easy.我们来看 很多同学在用分布 ...

  4. Redis分布式锁(图解 - 秒懂 - 史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  5. 阿里二面:redis分布式锁过期了但业务还没有执行完,怎么办

    面试官:你们系统是怎么实现分布式锁的? 我:我们使用了redis的分布式锁.具体做法是后端接收到请求后加入一个分布式锁,如果加锁成功,就执行业务,如果加锁失败就等待锁或者拒绝请求.业务执行完成后释放锁 ...

  6. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  7. 分布式锁的实现【转载】

    一.前言 经常遇到这样的情况,项目中需要使用分布式锁,发现没有完整的产品可以使用,就临时写个分布式锁,花费许多时间和精力来开发和测试一个简单的分布式锁,实现部分功能就使用了.后面遇到这种情况,又去重新 ...

  8. 【2020尚硅谷Java大厂面试题第三季 04】Redis 9种数据类型使用场景,分布式锁演变步骤,lua脚本,redis事务,Redisson,Redis内存占用,删除策略,内存淘汰策略,手写LRU

    1.安装redis6.0.8 2023 02 02 为:redis-7.0.8.tar.gz 2.redis传统五大数据类型的落地应用 3.知道分布式锁吗?有哪些实现方案?你谈谈对redis分布式锁的 ...

  9. java 通过redis实现倒计时_突破Java面试(42) - Redis amp; ZooKeeper两种分布式锁实现的优劣...

    0 Github 1 面试题 一般实现分布式锁都有哪些方式?使用redis如何设计分布式锁?使用zk来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? 2 考点分析 一般先问问你zk,然后 ...

最新文章

  1. input中v-model和value不能同时调用时解决方案
  2. 敏捷开发:软件与文档
  3. python正则表达式--分组、后向引用、前(后)向断言
  4. u盘安装ubuntu_简单实用的ubuntu18.04安装
  5. Cross_validation.train_test_split 中 stratify这个参数的意义是什么?
  6. VTK修炼之道20:图像基本操作_图像类型转换
  7. [CVPR2019]:专门为卷积神经网络设计的训练方法:RePr
  8. 理发店收银系统php,【毕业论文】基于php+mysql美发店收银系统设计与实现.doc
  9. total是什么牌子的电脑_干货!如何用Python在笔记本电脑上分析100GB数据(上)...
  10. c语言学习-编程实现以下功能,读入两个数(d1,d2)和一个运算符(o),计算d1 o d2的值
  11. 买的首套房开发商指定的银行是5.88的利率,朋友都说利率有点高,怎样才能省点钱呢?
  12. DR、BDR和DROther的关系之通俗演绎
  13. 应用安全-安全设备-Waf系列-软Waf-D盾
  14. 《数据结构》 李春葆 第一章-绪论
  15. php生成值班表,EXCEL表制作自动排列值班表【excel值班表表格制作教程】
  16. 2019公共课的【考研平均分】和难度系数公布!
  17. Oracle中SCOTT用户的 emp、dept、bonus、salgrade表的意思及其属性的意思
  18. [THUWC 2017]在美妙的数学王国中畅游
  19. 新浪押宝微博拖累利润 开支增长近2730万美元
  20. 【pwsh】按键自动切换中文输入法

热门文章

  1. 机器学习-浙江大学研究生课程
  2. TRACE32——Go.direct
  3. Pandas 分析斐波那契数列模整数的周期问题
  4. anaconda的安装和使用(管理python环境看这一篇就够了)
  5. 水仙花数(c++实现)
  6. 184644-83-5,MTSES用于研究蛋白质上的半胱氨酸残基
  7. 华钜同创:跨境运营培训班教你如何应对成本上涨
  8. python求雅可比矩阵_雅可比算法求矩阵的特征值和特征向量
  9. PayPal买家以”信用卡被盗刷”发起未授权争议要求退款怎么办?
  10. 通信原理之模拟幅度调制(线性调制)详解