共计 1497 个字符,预计需要花费 4 分钟才能阅读完成。
Redis 分布式锁
- 分布式锁的实现原理和不同形式的实现比照
- 基于 Redis 实现的分布式锁
集群架构下的并发问题
在单体架构上,乐观锁和乐观锁能够锁住并发状况下的同步代码块,咱们多应用 synchronized 来对办法加锁。然而在配上负载平衡的集群模式下,一般的 synchronized 是无奈锁住从两台服务器同时进入的申请。
这是在理解秒杀我的项目的难点之一:一人一单的并发平安问题 在应用集群架构呈现的难点。咱们先从 单体我的项目 登程,单体我的项目很好了解,如果有俩线程:线程 1 查问订单,判断是否存在。而后第二个线程之后在去查问订单,判断是否存在,在 synchronized 的作用下两个线程是不会产生问题的。
那当初,咱们不再是一台服务器,而是多台。在以后这一个 JVM 外部,锁的原理是在 JVM 外部保护了一个 锁监视器对象 ,监视器的对象用的是 userId,它是在咱们的 常量池 外面。那么在这个 JVM 外部是保护了这一个常量池子,当 ID 雷同的状况下,他们永远都是同一个锁,也就是说锁的监视器是同一个。所以无论是线程 1 也好,线程 2 也好,他们俩要获取锁的时候,锁监视器就会记录线程 ID,当另一个线程再来获取锁的时候必定是不行的,因为锁监视器曾经记录一个了。
然而,当咱们部署一个新的服务器的时候,也就是部署了一个新的 JVM。两个 JVM 也领有各自的常量池,JVM2 用 userId 作为锁的时候,它的监视器对象就会领有一个新的锁监视器,跟 JVM1 的监视器不是同一个。当初当咱们线程 3 来获取锁的时候走的是本人的监视器,那这个监视器显示的是空的呀,所以也能获取锁胜利,当然了线程 4 失败是没问题的。也就是说在 JVM 外部锁监视器能保障这些线程互斥,然而多个 JVM 就会有多个 JVM 监视器,有多少个锁监视器就会有多少个线程胜利进入同步代码块。
所以咱们要解决的问题就是在多个 JVM 的状况下让这些锁监视器应用同一把锁。
分布式锁的实现原理和不同形式的实现比照
synchronized 就是利用 JVM 外部的锁监视器来控制线程的,在 JVM 外部,因为只有一个锁监视器,所以只会有一个线程获取到锁,能够实现线程阶段互斥。然而当有多个 JVM 的时候,就会有多个锁监视器,这时候 synchronized 就会显得苍白无力,JVM 外部的锁监视器间接作废。所以锁的监视器肯定要在 JVM 的内部,让所有 JVM 都去找举世无双的锁监视器来获取锁,这样也就只有一个线程获取锁,也就实现了多 JVM 的线程互斥。
<mark> 所以满足在分布式系统或集群模式下 多线程可见 并且 互斥 的锁就是分布式锁 </mark>。
分布式锁外围是实现多过程之间的互斥,而满足这一点的形式有很多,常见的有三种:Mysql、Redis。Redis 里有 setnx
互斥命令,王 redis 面 set 数据的时候,只有没数据的时候才会 set 胜利,有数据就会 set 失败。
基于 Redis 实现的分布式锁
实现分布式锁必定要实现两个根本办法,获取锁 和 开释锁。
获取锁
- 互斥条件:确保只能有一个线程获取到锁。
- 非阻塞:尝试一次,胜利返回 true,失败返回 false。
这个咱们能够用 redis 的setnx
,这个能够确保只有一个能够返回 1。
确保原子性,利用 EX。
开释锁
- 手动开释 del lock
思考问题:如果在获取锁后 redis 宕机了,那么这个开释锁动作就永远得不到执行,其余线程进不来,我这服务曾经挂了,整个线程进入死锁状态。所以须要在获取锁时增加过期工夫,防止服务器宕机引起的死锁。
Redis 分布式锁 1.0
锁的名称不能写死,不同的业务有不同的锁。
欢送关注我的公众号:敲代码的老贾,回复“支付”赠送《Java 面试》材料,阿里,腾讯,字节,美团,饿了么等大厂