Java之分布式锁的5种实现过程

 更新时间:2025年09月13日 09:19:02   作者:右手嘚温暖  
这篇文章主要介绍了Java之分布式锁的5种实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

1、分布式锁的基本概念

分布式锁是在分布式系统环境下,控制多个进程/服务/主机互斥访问共享资源的核心协调机制。

它解决了单机锁(如Java的synchronized、ReentrantLock)在分布式场景下失效的问题,是构建可靠分布式应用的必备工具。

解决我们在多个jvm中最终只能有一个jvm执行,从而保证了幂等性的问题。

2、业务超时,一直不释放锁如何处理?

可以采用续命设计,续命多次,如果业务还是没有执行完毕,则认为超时,应该主动释放该锁,防止其他jvm一直阻塞等待。

  • (1)主动释放锁;
  • (2)回滚当前业务逻辑;
  • (3)主动停止该线程;
  • (4)移除监听。

3、集群环境中保证定时任务执行的幂等性问题

幂等性:

  • 执行结果保证唯一不能够重复。
  • 当我们定时任务服务集群的情况下,有可能会同时重复执行定时任务

解决思路:

  • 多个jvm集群的定时任务,在触发的时候,获取分布式锁,
  • 如果能够获取到分布式锁的jvm,就能够执行定时任务,没有获取到的就不能执行定时任务。

4、基于zookeeper实现分布式锁

(1)实现分布式锁思路:

因为Zookeeper节点路径保持唯一,不允许重复,且有临时节点特性,连接关闭后当前节点会自动消失,从而实现分布式锁。

(2)实现原理:(临时节点+事件通知)

  • 多个jvm请求同时创建相同的临时节点(lockPath),只要谁能够创建成功谁就能够获取到锁;
  • 如果创建节点的时候,突然该节点已经被其他请求创建的话则直接等待;
  • 只要能够创建节点成功,则开始进入到正常业务逻辑操作,其他没有获取到锁的jvm进行等待;
  • 正常业务逻辑流程执行完后,调用zk关闭连接方式释放锁,从而使其他的请求开始进入到获取锁的资源。

疑问:如果使用zk实现分布式锁,获取锁之后业务逻辑方法一直没有执行完毕,导致其他所有的请求等待的话如何解决?

设置Session连接超时时间,在规定的时间内获取锁后超时啦~自动回滚当前数据库业务逻辑。

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

(1)悲观锁

  • 就是先select…forupdate锁住主键key_resource那个记录,如果为空,则可以插入一条记录,如果已有记录判断下状态和时间,是否已经超时。
  • 这里需要注意一下哈,必须要加事务哈。

(2)搞个version字段

  • 每次更新修改,都会自增加一,然后去更新余额时,把查出来的那个版本号,带上条件去更新,
  • 如果是上次那个版本号,就更新,如果不是,表示别人并发修改过了,就继续重试。)

6、基于redis实现分布式锁

(1)采用Setnx

Redis中SetnX与Set命令的区别

  • Setnx可以返回该key是否存在,存在返回0,不存在返回1,如果该key存在的情况下,是不能做修改的。
  • Set每次直接覆盖该key对应的value。

获取锁的原理:

  • 多个redis客户端执行setNx命令,设置一个相同的redis的key,谁能创建key成功,谁就能获取锁,
  • 如果该key已经存在的情况下,则再创建的时候会返回false。

释放锁的原理:

  • 删除该key。

7、基于redisson实现分布式锁

多个jvm同时在redis中写入一个相同的key,谁能够写入成功,谁就能获取到锁。

(1)向redis中写入key的时候使用lua脚本,不是setNx;

(2)如果写入key成功,会单独开启一个看门狗线程(续命定时任务线程),默认的情况下每隔10s时间不断续命延迟。

(3)一直不断实现续命的情况下,也会发生死锁问题,此时设定续命的次数,续命多次如果业务逻辑还没有执行完毕,主动回滚当前的mysql事务,并释放该锁。

8、基于Curator实现分布式锁(解决羊群效应问题)

核心思想:

(1)从缓存中查找是否已经创建分布式锁,如果已经创建了分布式锁,则直接复用(具有可重入性)。

(2)如果缓存中没有,则创建一个分布式锁。

(3)实现原理:创建一个临时节点,获取当前父节点下的子节点,如果是为最小的节点,则表示获取锁成功,否则获取锁失败,阻塞等待,则监听上一个节点。

(4)当上一个节点如果释放锁之后,直接进入到获取锁的状态,唤醒使用waitnotify技术。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java高效提取PDF文件指定坐标的文本内容实战代码

    Java高效提取PDF文件指定坐标的文本内容实战代码

    在日常工作中,有时可能会需要从庞大的PDF文档中提取其中所包含的文本内容,下面这篇文章主要给大家介绍了关于如何利用Java高效提取PDF文件指定坐标的文本内容,需要的朋友可以参考下
    2024-01-01
  • 详解java基于MyBatis使用示例

    详解java基于MyBatis使用示例

    这篇文章主要介绍了详解java基于MyBatis使用示例,对学习MyBatis有一定的帮助,有需要的可以了解一下。
    2016-11-11
  • Java设计模式之开闭原则精解

    Java设计模式之开闭原则精解

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。本篇介绍设计模式七大原则之一的开闭原则
    2022-02-02
  • spring boot创建项目包依赖问题的解决

    spring boot创建项目包依赖问题的解决

    本篇文章主要介绍了spring boot创建项目包依赖问题的解决,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Java文件(io)编程之记事本开发详解

    Java文件(io)编程之记事本开发详解

    这篇文章主要为大家详细介绍了Java文件(io)编程之记事本开发,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • JavaWeb中的常用的请求传参注解说明

    JavaWeb中的常用的请求传参注解说明

    这篇文章主要介绍了JavaWeb中的常用的请求传参注解说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • java中利用栈实现字符串回文算法

    java中利用栈实现字符串回文算法

    给定一个由多个a和b组成的字符串数组,字符串中有一个特殊的字符X,位于字符串的正中间,例如(aaaabbbbXabaabbbb),如何判定该字符串是否回文
    2020-12-12
  • 如何处理后台向前台传递的json数据

    如何处理后台向前台传递的json数据

    这篇文章主要介绍了如何处理后台向前台传递的json数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • DUBBO 日志过滤器,输出dubbo 接口调用入参、出参等信息(最新推荐)

    DUBBO 日志过滤器,输出dubbo 接口调用入参、出参等信息(最新推荐)

    这篇文章主要介绍了DUBBO 日志过滤器,输出dubbo 接口调用入参、出参等信息,首先自定义一个过滤器 DubboLoggerFilter.java,本文结合示例代码给大家讲解的非常详细,需要的朋友可以参考下
    2022-12-12
  • Java SSM框架如何配置静态资源加载

    Java SSM框架如何配置静态资源加载

    这篇文章主要介绍了Java SSM框架如何配置静态资源加载,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04

最新评论