前言

随着互联网的发展,人们网上购物已然成为常态,特别是双十一和618等大型的购物节,网站的并发数量也急剧上升,因此我们后台的框架也逐渐从以前的单机版升级到现在的分布式集群。这一切的演变最终目的都是为了提升系统性能,给用户带来更好的购物体验。在曾今的单机环境下多线程的并发抢夺资源的情况我们用SynchronizedReentrantLock都可以完美的解决,但是由于现在的环境是同一个服务有多个节点,当同一个服务的多个节点同时操作某一个公共资源时我们又该如何去解决这个问题呢?这就是提到过的分布式锁的问题

一、什么是分布式锁

首先分布式锁的这个概念只有在分布式集群环境下才有,单机版的系统中不存在这个概念。在单机版的系统中我们为解决多线程抢夺共享资源的问题引入了Synchronized和ReentrantLock两种单机锁,那么分布式锁其实也是一个道理,是一种专门解决分布式集群环境下多个jvm抢夺共享资源的一种处理手段。下面举个比较恶心的例子来说明单机锁和分布式锁:
前提:假如一层楼只有一个厕所并且只有一个坑位,每次只能去一个人
单机锁:

该层楼只有一个办公室,为了防止多人抢夺坑位,就给办公室的大门上了一把锁,并且锁只有一把钥匙,因此需要上厕所就必须拿到办公室的钥匙才可以。(注意此时上锁的对象是办公室的大门)

分布式锁:

该楼层有多个办公室,如果依旧采用单机锁也就是给每个办公室的都上一把锁,此时会发现还是会出现抢占坑位的情况,因为每个办公室是独立的。因此这种情况我们就需要给厕所门上一把锁,让所有办公室的人去抢夺这个厕所门的锁,而不是给每个办公室的门上一把锁,如此我们才能解决多个办公室场景下的抢夺资源问题。

以上案例中,厕所就是我们需要抢夺的资源,而办公室就是我们程序运行的jvm,办公室中的每个人就是每个jvm中运行的线程。

二、分布式锁应该具备哪些条件

1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
2、高可用的获取锁与释放锁;
3、高性能的获取锁与释放锁;
4、具备可重入特性;
5、具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。

三、如何实现分布式锁

分布式锁的实现常用方式有如下三种:

  • MySQL数据库实现:基于数据库的乐观锁实现(工作中不推荐使用)

  • Redis数据库实现:基于Redisson实现、基于Lua脚本实现(推荐)

  • Zookeeper数据:基于Zookeeper中不能创建相同的临时节点二实现

四、Redis实现分布式锁(推荐)

1.实现流程

①获取锁
②执行业务逻辑
③释放锁
其实我们分布式锁中主要解决的问题就是上锁和解锁过程的原子性,只要保证了上锁和解锁过程的原子性以及保证锁在异常情况下锁能够得到释放。

2.搭建基础框架环境(springboot+redis+mysql+MybatisPlus)
2.实现方式

用lua脚本实现:

 /** 添加分布式锁,用lua脚本方式 */private String getDataByLua(Long userId) {// 抢占分布式锁String value = UUID.randomUUID().toString().replaceAll("-", ""); // 当前锁的指Boolean lock =redisTemplate.opsForValue().setIfAbsent(ConstantUtil.REDIS_USER_LOCK_KEY + userId, value, 300, TimeUnit.SECONDS);String fromDb = "";if (lock) {System.out.println("获取分布式锁成功!");try {fromDb = getDataFromDb(userId);} finally {// 删除分布式锁,传入value,确保删除的是自己的锁String script ="if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n"+ "    return redis.call(\"del\",KEYS[1])\n"+ "else\n"+ "    return 0\n"+ "end";redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList("lock"), value);}} else {System.out.println("获取分布式锁失败,等待重试!");try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}return getDataByLua(userId);}return fromDb;}

Redisson实现:

  private String getDataByRedison(Long userId) {RLock lock = redissonClient.getLock(ConstantUtil.REDIS_USER_LOCK_KEY + userId);// 阻塞式等待,默认锁为30S,业务执行期间看门狗会自动续锁,业务执行完如果不手动删除锁,30S后自动删除lock.lock();String fromDb = "";try {System.out.println("加锁成功,执行业务"+Thread.currentThread().getId());fromDb = getDataFromDb(userId);} finally {System.out.println("释放锁"+Thread.currentThread().getId());lock.unlock();}return fromDb;}

五、相关资料

Redis分布式锁官方汉化版文档:http://www.redis.cn/topics/distlock.html
本示例demo链接:www.baidu.com
Redisson源码教程链接:https://github.com/redisson/redisson

六、小结

我自己只研究过用redis来实现,在项目中也看到老大用redis来实现的,不过他是用lua脚本的方式实现的,至于为什么不用redisson来实现我也不得而知,其实两种方法都是一样的,因为redisson的底层其实也是通过lua脚本来实现的。至于mysql和zookeeper的实现方式,大家也可以去学习一下。

分布式锁详解及实现案例相关推荐

  1. Redis分布式锁详解

    Redis分布式锁详解 1. 分布式所概述 1.1 分布式锁 2. 缓存数据库Redis 2.1 redis简介 2.2 Springboot整合Redis两种方式 3. 实现验证 3.1 环境准备 ...

  2. Redis缓存雪崩、穿透、击穿,布隆过滤器,分布式锁详解

    缓存雪崩 在某一个时间存在大量的缓存key失效 解决办法 1.有效期一直---->给每一个数据加上水机有效期 2.redis挂掉了----->使用redis集群,分摊key的存储 引出re ...

  3. SpringCloud Alibaba 之 Config配置中心,Redis分布式锁详解

    目录 1.服务配置中心 1.1 服务配置中心介绍 1.2 Nacos Config 实践 1.2.1 Nacos config 入门案例 1.2.2  Nacos 配置动态刷新 1.2.3 配置共享 ...

  4. Redis的分布式锁详解

    一.什么是分布式锁: 1.什么是分布式锁: 分布式锁,即分布式系统中的锁.在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题.与单体应用不同 ...

  5. 干货,springboot自定义注解实现分布式锁详解

    背景 在互联网的很多场景下,会产生资源竞争,如果是单机环境,简单加个锁就能解决问题:但是在集群环境下(分布式环境),多个客户端在一个很短的时间内竞争同一服务端资源(如抢购场景),或者同一客户端重复提交 ...

  6. 并发场景下的幂等问题——分布式锁详解

    简介:本文从钉钉实人认证场景的一例数据重复问题出发,分析了其原因是因为并发导致幂等失效,引出幂等的概念.针对并发场景下的幂等问题,提出了一种实现幂等可行的方法论,结合通讯录加人业务场景对数据库幂等问题 ...

  7. 实战:分布式锁详解与代码

    什么是锁? 锁是一种常用的并发控制机制,用于保证一项资源在任何时候只能被一个线程使用,如果其他线程也要使用同样的资源,必须排队等待上一个线程使用完. 锁的示意图,如下所示: 什么是分布式锁? 上面说的 ...

  8. java分布式锁详解

    一.什么是分布式锁 分布式锁是一种在分布式系统中,用来保护共享资源的一种机制,当多个线程或进程同时访问共享资源时,可以通过分布式锁来保护,保证共享资源只能被一个线程或进程访问,以实现共享资源的安全访问 ...

  9. Redisson分布式锁详解

    概述 setnx分布式锁的问题 重入问题 重入问题是指获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,它的方法都是使用synchroniz ...

最新文章

  1. android int与String的转换
  2. IOS基础之绘图函数的使用
  3. 从物联网发展历程看区块链挑战
  4. Visual studio docker build no such file or directory
  5. 目标检测——评价指标的学习笔记
  6. iphone保修期多久_小心!教你如何鉴别 iPhone 翻新机,黑机千万别买!
  7. 华为的创新——流程和组织结构
  8. Java基础篇:什么是FileWriter
  9. Pure-ftpd无法连接到服务器 425错误
  10. argparse模块用法
  11. docker 发布springBoot项目
  12. 1.《Spring学习笔记-MVC》系列文章,讲解返回json数据的文章共有3篇,分别为:...
  13. ​突破数据存储瓶颈,Aibee实现场景化AI的有效落地
  14. php smarty 模板注释,smarty中的注释
  15. Date 日期时间工具类,针对日期的一些常用的处理方法
  16. 如何科学评估疫情对业务的影响?
  17. HEVC vs AVS2
  18. 【无标题】(2019)NOC编程猫创新编程复赛小学组真题含参考
  19. Google退出Android有影响吗?
  20. 系统关键文件丢失或损坏

热门文章

  1. 数据化管理洞悉零售及电子商务——数据分析方法
  2. swift学习-闭包
  3. 类脑传感器:动态视觉相机(Dynamic Vision Sensor)和动态音频传感器(Dynamic Audio Sensor)
  4. 图扑推出可视化智慧仓储管理系统,能否解决购物狂欢节爆仓危机?
  5. 字符串中单词翻转并大小写转换
  6. mysql COLLATE=utf8mb4_unicode_ci
  7. oracle sqltune,oraclet通过DBMS_SQLTUNE.EXECUTE_TUNING_TASK获取优化建议
  8. jenkings - instead of the expected OK message
  9. VS Code编译file not found问题
  10. 已知一点经纬度,方位角,距离,求另一点经纬度