当前位置: 首页> 财经> 创投人物 > 解答网站内容优化策略_注册平台需要什么条件_网络营销策划书2000字_必应站长平台

解答网站内容优化策略_注册平台需要什么条件_网络营销策划书2000字_必应站长平台

时间:2025/8/13 22:55:28来源:https://blog.csdn.net/qq_36268103/article/details/144903388 浏览次数:0次
解答网站内容优化策略_注册平台需要什么条件_网络营销策划书2000字_必应站长平台

为什么要有分布式锁 分布式锁是基于什么延伸出来的?这个可以在博主首页搜索:超卖, 里面通过超卖例子说明分布式锁和传统锁的区别,本文重点阐述的是redisson的api使用及其源码分析。

文章目录

  • springboot整合redisson
  • redisson三个重要参数
    • leaseTime
    • waitTime
    • lockWatchdogTimeout
  • redisson常用api
  • api源码简析
    • leaseTime和watchDog不能共存的原因
    • lock同步阻塞的原因

springboot整合redisson

    <!-- redisson--><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.16.5</version></dependency>
@Configuration
@EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {// 创建 Redisson 配置Config config = new Config();SingleServerConfig singleServerConfig = config.useSingleServer();// 配置 Redis 连接地址(假设是单机版 Redis)singleServerConfig.setAddress("redis://xx.xx.xx.xxx:6379");singleServerConfig.setDatabase(1);singleServerConfig.setPassword("xxxxxxx");// 创建并返回 RedissonClientreturn Redisson.create(config);}/*** 哨兵模式配置*/
//    @Bean
//    public RedissonClient createClient() {
//        // 创建配置对象
//        Config config = new Config();
//
//        // 使用 JSON 编解码器
//        config.setCodec(new JsonJacksonCodec());
//
//        // 配置哨兵模式
//        SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
//        // 配置哨兵地址,多个哨兵地址之间用逗号分隔
//        sentinelServersConfig.setSentinelAddresses(Arrays.asList(
//                "redis://xx.xx.xx.xxx:26379", "redis://xx.xx.xx.xxx:26380","redis://xx.xx.xx.xxx:26381"
//        ));
//
//        // 配置主 Redis 实例名称
//        sentinelServersConfig.setMasterName("mymaster");
//
//        // 配置数据库索引(Redis 默认是 0)
//        sentinelServersConfig.setDatabase(0);
//
//        // 配置哨兵认证密码
//        sentinelServersConfig.setPassword("xxxxx");
//
//        /**
//         * 设置连接池的最大连接数、最小连接数等参数(可选)
//         */
//        // 设置连接超时为 10 秒
//        sentinelServersConfig.setConnectTimeout(10000);
//        // 设置操作超时为 3 秒
//        sentinelServersConfig.setTimeout(3000);
//        // 设置重试次数
//        sentinelServersConfig.setRetryAttempts(3);
//        // 设置重试间隔为 1.5 秒
//        sentinelServersConfig.setRetryInterval(1500);
//
//        // 返回 Redisson 客户端
//        return Redisson.create(config);
//    }}

redisson三个重要参数

leaseTime

  1. leaseTime
    锁自动释放时间(或者理解为锁持有时间,持有30s和30s释放是一个意思),当出现异常 或者没手动释放锁,在到了自动释放时间时,会自动将锁释放

waitTime

  1. waitTime
    等待重试时间,有点像java原生定时器的延迟执行时间,当前线程发现锁已经被其它线程持有了(当前线程获取锁失败,通俗点解释就是 代码已经被上锁了 资源被占用了), 是应该直接重试呢 还是等待一段时间重试呢? 这种选择就是通过waitTime来控制的,当waitTime = 0时,那当前线程会马上重新尝试获取锁;如果waitTime为不为0 例如为30s, 那么当前线程会在30s再重试 尝试获取锁,如果获取成功则继续执行。

    由此也会延伸出一个疑问:如果waitTime时间设置过长或过短 会对锁造成什么影响吗?
    答案是否定的,不会造成死锁,在一般的项目中waitTime只要不是太不合理都问题不大;
    那我们严格分析一下,在高并发的项目中会发生什么:
    如果waitTime过短,那它会多次尝试 造成不必要的资源损耗 ;
    那如果waitTime > leaseTime (假设实际释放时间 = leaseTime )呢? 那可能等着等着已经被其它线程占用了
    (虽然是lua脚本,但是只是脚本执行的时候是原子性的!比如一个脚本设置过期时间为1h 不是这1h原子性操作 而是执行脚本一瞬间是原子操作)

lockWatchdogTimeout

  1. watchDog看门狗,注意是和leaseTime互斥的!可以简单理解为:如果都强制说明了锁释放时间,那么也就不需要锁续命机制了,watchDog的默认时间是30秒,可以在配置Redisson的时候 Config里面自行修改;

    看门狗主要解决的是 我们可能没法很好的评估线程执行完的时间,声明时间很可能导致锁提前释放;redisson的watchDog机制 发现线程没结束 会锁续命,保证线程完全处于加锁状态中。

    这里博主曾陷入一个误区,如果业务始终不完成 例如死循环 锁岂不是一直不释放 就成了死锁?
    答案虽然是肯定的,但是这不是我们该考虑的范畴,业务死循环 有没有锁 都会OOM的 这不应该是我们写出来的业务代码,应该从源头去避免这个问题。

redisson常用api

  1. lock()
    lock是阻塞锁,没获取到锁会一直阻塞等待:

     线程1加锁 ->线程2阻塞等待 ->线程1释放锁 ->线程2加锁 ->线程2释放锁
    
  2. tryLock()
    tryLock是异步锁,如果发现获取锁失败 会直接返回false,我们可以手动判断加锁结果 做不同的业务 (比如false中直接return表示不等待 视为失败)

    以上两个api默认都是有watchDog机制的 ,因为没有显式的指定leaseTime。

  3. tryLock(long waitTime, long leaseTime, TimeUnit unit)
    有严谨的同学,希望完全自己掌控时间(我命由我 不由框架),会选择自己定义锁释放的时间,但是定义了leaseTime,watchDog机制就失效了。

    缺点:可能会和延迟双删一样的问题了,锁可能会提前释放,也可能预估不准确。
    优点:保证锁在一定时间内会释放 不会阻塞。

api源码简析

leaseTime和watchDog不能共存的原因

不管是lock还是tryLock,我们不显式声明leaseTime的时候,它内部都是声明-1,
在这里插入图片描述
主要是在tryAcquire方法里面判断:
在这里插入图片描述

当配置了leaseTime,则以leaseTime为准,如果没配置 ,则会使用watchDog的时间,且会不断续命(并不是只用一次watchDog的时间就释放锁)
在这里插入图片描述

我们也可以用demo来验证一下:

锁没有提前释放例子
在这里插入图片描述

声明了leaseTime ,watchDog失效的例子

当我们声明leaseTime = 10s , 在10s就会自动将锁释放,等到我们业务代码执行30s后,再去手动释放锁会提示unlock失败 并报错: attempt to unlock lock, not locked by current thread by node id xxx

所以需要在实际业务中,我们手动释放锁要加一个判断
if (lock.isHeldByCurrentThread())
否则会抛异常在这里插入图片描述

(为什么有了自动释放 还需要手动释放呢? 还是那句话 我命由我,自动的时间可能会受一些意想不到的因素影响,例如网络、jvm的gc导致的stw)

lock同步阻塞的原因

lock源码 朴实无华的同步方法
在这里插入图片描述

我们可以对比一下tryLock是怎么做的:
在这里插入图片描述
只看方法名可能不太够,我们稍微追踪一下源码(过程比较简单 就不一一贴出来了) 追踪几步后可以看到异步执行的代码:
在这里插入图片描述

关键字:解答网站内容优化策略_注册平台需要什么条件_网络营销策划书2000字_必应站长平台

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: