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面试》材料,阿里,腾讯,字节,美团,饿了么等大厂