Java面试专题-redis篇分布式锁

二、分布式锁

1.使用场景

  • redis分布式锁,是如何实现的?

需要结合项目中的业务进行回答,通常情况下,分布式锁使用的场景:

集群情况下的定时任务、抢单、幂等性场景

例:抢券场景:

/ **
*抢购优惠券
*@throws InterruptedException
*/

public void rush ToPurchase() throws InterruptedException {
    //获取优惠券数量

    Integer num = (Integer) redisTemplate.opsForValue().get("num");
    //判断是否抢完
    if (null == num || num <= 0) {
    throw new RuntimeException(“优惠券已抢完”);

    }
    //优惠券数量减一,说明抢到了优惠券

    num = num - 1;

    //重新设置优惠券的数量
    redis Template.opsForValue().set("num", num);
}

抢券执行流程:

1.正常情况下:

alt

2.库存只剩1个的情况

超卖情况(库存 -1)

alt

3.先使用synchronied锁
public void rush ToPurchase() throws InterruptedException {
    synchronized (this){
        //查询优惠券数量
        Integer num = (Integer) redisTemplate.opsForValue().get("num");
        //判断是否抢完
        if (null == num || num <= 0) {
        	throw new RuntimeException("商品已抢完");
        }
        //优惠券数量减一(减库存)
        num = num - 1;
        //重新设置优惠券的数量
        redisTemplate.opsForValue().set("num", num);
    }
}

alt

如果项目是单体项目,并且只启动了一台服务,这个代码就没有问题。

4.服务集群部署

但是一般为了满足并发请求,会把服务网做成集群部署。

alt

每个服务都有各自的JVM,解决不了多个JVM下线程的互斥

alt

所以在这种情况下,要使用外部的锁来解决——分布式锁

alt

2.实现原理(setnx, redisson)

redis分布式锁:

1.setnx

redis实现分布式锁主要利用redis的setnx命令。setnx是SET if not exists(如果不存在,则SET)的简写。

  • 获取锁:

    # 添加锁,NX是互斥、EX是设置超时时间
    SET lock value NX EX 10
    
    • 一条命令保证原子性

    • 不设置超时时间可能会导致死锁

  • 释放锁:

    # 释放锁,删除即可
    DEL key
    

alt

  • redis实现分布式锁如何合理的控制锁的有效时长?

    根据业务执行时间预估(不太合适)

    给锁续期 ---> redisson

2.redisson

加锁成功之后,另开一个线程进行监控

手动释放锁

public void redisLock() throws InterruptedException {
    //获取锁(重入锁),执行锁的名称
    RLock lock = redissonClient.getLock( s: "heimalock");
    //尝试获取锁,参数分别是:获取锁的最大等待时间(期间会重试),锁自动释放时间,时间单位
    //boolean isLock = lock.tryLock(10,30, TimeUnit.SECONDS);
    boolean isLock = lock. tryLock ( time: 10, TimeUnit. SECONDS);
    //判断是否获取成功
    if (isLock) {
        try {
        	System.out.println("执行业务”);
        } finally {
        	//释放锁
        	lock. unlock();
        }
    }
}

加锁、设置过期时间等操作都是基于lua脚本完成

alt

重入
  • redisson实现的分布式锁是否可以重入呢?

可以,要判断是不是同一个线程,是就可重入

public void add 1(){
    RLock lock = redissonClient.getLock("heimalock");
    boolean isLock = lock.tryLock();
    //执行业务
    add2();
    //释放锁
    lock.unlock();
}
public void add2(){
    RLock lock = redissonClient.getLock("heimalock");
    boolean isLock = lock.tryLock();
    //执行业务
    //释放锁
    lock.unlock();
}

利用hash结构记录线程id重入次数

KEY VALUE
field value
heimalock thread1 2
主从一致性
  • redisson实现的分布式锁能保证主从数据的一致吗?

    当主节点还没来得及同步数据,他挂了,宕机,那么依据redis的哨兵模式,他会在从节点中选择一个当作主节点

    这时候,两个线程同时持有一把锁,不满足互斥性了,可能会出现脏数据

alt

所以,提出红锁

RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁**(n/2+1)**,避免在一个redis实例上加锁。 alt

一般不常使用:实现复杂!性能差!运维繁琐!

redis整体集群是AP思想 (高可用)

如果要保证强一致,建议使用CP思想的zookeeper

总结

  • redis分布式锁,是如何实现的?

​ ● 先按照自己简历上的业务进行描述分布式锁使用的场景 ​ ● 我们当使用的redisson实现的分布式锁,底层是setnxlua脚本(保证原子性)

  • Redisson实现分布式锁如何合理的控制锁的有效时长?

    在redisson的分布式锁中,提供了一个WatchDog(看门狗),一个线程获取锁成功以后,WatchDog会给持有锁的线程续期(默认是每隔10秒续期一次)

  • Redisson的这个锁,可以重入吗?

    可以重入,多个锁重入需要判断是否是当前线程,在redis中进行存储的时候使用的hash结构,来存储线程信息和重入的次数

  • Redisson锁能解决主从数据一致的问题吗

    不能解决,但是可以使用redisson提供的红锁来解决,但是这样的话,性能就太低了,如果业务中非要保证数据的强一致性,建议采用zookeeper实现的分布式锁

#计算机有哪些岗位值得去?##简历中的项目经历要怎么写##牛客解忧铺#
java面试专题学习记录 文章被收录于专栏

开始看黑马Java面试,27届的,大家有什么建议欢迎来说哟

全部评论
uu的redis八股感觉还不错呀,是自己写的还是网上资源呀
点赞 回复 分享
发布于 昨天 00:51 山东
哇,你对Redis分布式锁的理解真的很深入呢!👍 在项目中使用分布式锁确实能解决很多并发问题。我有个小问题,如果我们项目中遇到锁过期了但是业务还没执行完的情况怎么办呢?😖 对了,如果你对Redis分布式锁还有其他疑问,或者想要了解更多细节,可以点击我的头像,给我发私信哦,我们可以一起深入探讨~🐮🎉 另外,Redisson真的很好用呢,它的看门狗机制真的很智能,能够帮助我们自动续期,减少死锁的风险。你对Redisson的其他特性也感兴趣吗?我们可以聊聊它的其他用途和优势哦!🤔🌟
点赞 回复 分享
发布于 12-20 00:12 AI生成

相关推荐

12-20 09:21
门头沟学院 Java
作为经历过秋招的过来人,选实习我早就想明白了:优先级必须是&nbsp;“title>经验>薪资”,尤其是对校招党来说,这顺序真的能少走很多弯路!首先说为什么&nbsp;title&nbsp;是重中之重,这真的是简历的&nbsp;“敲门砖”。秋招投简历的时候就发现,大厂或者知名公司的实习&nbsp;title,比啥都管用&nbsp;——HR&nbsp;筛简历的时候,第一眼扫到&nbsp;“XX&nbsp;大厂后端开发实习生”“XX&nbsp;知名企业技术岗实习”,至少会给你笔试机会;但如果是没听过的小公司,哪怕你写了一堆&nbsp;“参与&nbsp;XX&nbsp;项目”,大概率也是石沉大海。之前身边有同学,实习薪资给得挺高,但公司没名气,秋招投了几十家都没回应;而我因为有过大厂实习&nbsp;title,简历初筛通过率明显高很多,甚至有&nbsp;HR&nbsp;面试时直接说&nbsp;“你之前的实习公司挺不错,我们很看重这个”。对实习生来说,title&nbsp;就是&nbsp;“背书”,没有好&nbsp;title,后面的经验再丰富,可能都没机会让面试官看到。然后是经验,这是实习的核心价值。我们出来实习,根本不是为了赚那点工资,而是为了攒&nbsp;“能聊、能用”&nbsp;的经验。好的实习能让你接触到规范的项目流程,比如需求评审、代码走查、测试上线,还能学到真实业务场景下的技术应用&nbsp;——&nbsp;比如我之前的实习,跟着前辈做高并发模块,学会了&nbsp;Redis&nbsp;缓存优化、分布式事务处理,这些都是课本上学不到的,面试时能说清项目细节、技术难点,比空泛地说&nbsp;“我学了&nbsp;Spring&nbsp;Boot”&nbsp;管用多了。反过来,要是选了薪资高但没技术含量的实习,每天就干整理数据、改简单&nbsp;bug&nbsp;的活,学不到核心东西,实习结束后简历都没的写,纯属浪费时间。最后是薪资,真的可以往后放。对实习生来说,薪资差距其实不大,最多也就一两千块钱的区别,这点钱对长期职业发展来说,影响微乎其微。与其盯着短期高薪,不如选一个&nbsp;title&nbsp;响、能学东西的实习,等秋招拿到好&nbsp;offer,薪资自然会翻倍;要是为了这点小钱选了没价值的实习,秋招时竞争力不足,最后可能连好工作都找不到,得不偿失。
选实习,你更看重哪方面?
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务