分布式锁之强大的Redisson

作者:微信小助手

发布时间:2023-10-23T09:53:05

STRAT

乘风破浪 | 直挂云帆

Redisson是基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。能够为我们提供多服务版并发解决的能力,大大降低分布式系统的难度。

使用与底层结构


主要的使用时集成到Springboot中,首先引入pom依赖,然后引入配置。

         </ul>
         <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer">&lt;dependency&gt;</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&lt;groupId&gt;org.redisson&lt;/groupId&gt;</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&lt;artifactId&gt;redisson&lt;/artifactId&gt;</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&lt;version&gt;3.11.1&lt;/version&gt;</span></code><code><span class="code-snippet_outer">&lt;/dependency&gt;</span></code></pre>
        </section>
        <section class="code-snippet__fix code-snippet__js">
         <ul class="code-snippet__line-index code-snippet__js">
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
         </ul>
         <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer" style="color: rgb(175, 175, 175);">@Configuration</span></code><code><span class="code-snippet_outer"><span style="color: rgb(202, 125, 55);">public</span> <span style="color: rgb(202, 125, 55);">class</span> <span style="color: rgb(14, 156, 229);">RedissonConfig</span> {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);">@Value("<span style="color: rgb(202, 125, 55);">${spring.redis.host}</span>")</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">private</span> String host;</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);">@Value("<span style="color: rgb(202, 125, 55);">${spring.redis.port}</span>")</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">private</span> String port;</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);">@Value("<span style="color: rgb(202, 125, 55);">${spring.redis.password}</span>")</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">private</span> String password;</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);">@Value("<span style="color: rgb(202, 125, 55);">${spring.redis.database}</span>")</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">private</span> int database;</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);">@Bean</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">public</span> RedissonClient getRedisson() {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;Config config = new Config();</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);font-style: italic;">//线程定时间隔时间10s</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;config.setLockWatchdogTimeout(<span style="color: rgb(14, 156, 229);">10000</span>);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);font-style: italic;">//设置单机版本redis</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;config.useSingleServer().setAddress(<span style="color: rgb(221, 17, 68);">"redis://"</span> + host + <span style="color: rgb(221, 17, 68);">":"</span> + port).setPassword(password).setDatabase(database);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);font-style: italic;">//设置集群的方式</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;config.useClusterServers().addNodeAddress(<span style="color: rgb(221, 17, 68);">"redis://"</span> + host + <span style="color: rgb(221, 17, 68);">":"</span> + port);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);font-style: italic;">//添加主从配置</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;config.useMasterSlaveServers().setMasterAddress(<span style="color: rgb(221, 17, 68);">""</span>).setPassword(<span style="color: rgb(221, 17, 68);">""</span>).addSlaveAddress(new String[]{<span style="color: rgb(221, 17, 68);">""</span>,<span style="color: rgb(221, 17, 68);">""</span>});</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">return</span> Redisson.create(config);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;}</span></code><code><span class="code-snippet_outer">}</span></code></pre>
        </section>
        <p style="margin: 24px 8px;line-height: 1.75em;"><span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">底层结构:</span></p>
        <section data-tools="135编辑器" data-id="119830">
         <section style="margin: 10px auto;">
          <section>
           <section style="display: flex;">
            <section style="flex-shrink:0;">
             <section style="background-color: #7f7f7f;height: 100%;">
              <section style="padding-top: 20px;padding-right: 2px;padding-left: 2px;">
               <section style="width: 15px;">
                <img class="rich_pages wxw-img" data-ratio="2.0987124463519313" data-type="gif" data-w="466" data-width="100%" style="vertical-align: inherit;width: 100%;display: block;height: auto !important;" src="/upload/edf29291b98f0aee1f8d6e3fd69b2f30.png">
               </section>
              </section>
             </section>
            </section>
            <section style="background-color: rgb(242, 249, 255);width: 100%;" data-width="100%">
             <section style="padding-top: 15px;padding-right: 15px;padding-left: 15px;">
              <section data-autoskip="1" style="text-align: justify;line-height:1.75em;letter-spacing: 1.5px;font-size:14px;color:#333333;background: transparent;">
               <p style="margin: 8px;line-height: 1.75em;"><span style="max-inline-size: 100%;cursor: text;text-align: left;caret-color: rgb(255, 0, 0);font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);outline: none 0px !important;">一个分布式锁对应一个hash</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;"><span style="max-inline-size: 100%;cursor: text;text-align: left;caret-color: rgb(255, 0, 0);outline: none 0px !important;">,</span><span style="max-inline-size: 100%;cursor: text;text-align: left;caret-color: red;font-family: 微软雅黑, &quot;Microsoft YaHei&quot;, sans-serif;outline: none 0px !important;">hash 对应的 key 为分布式锁的名字。例如说,我们锁定某个商品的库存,则 key 可以是 "product_stock_01"。</span></span></p>
               <p style="margin: 8px;line-height: 1.75em;"><br></p>
               <p style="margin: 8px;line-height: 1.75em;"><span style="font-size: 15px;background-color: transparent;caret-color: red;color: rgb(96, 96, 96);letter-spacing: 1px;">hash 里面</span><span style="font-size: 15px;background-color: transparent;caret-color: red;letter-spacing: 1px;color: rgb(255, 76, 0);">只有一对 field value 键值对</span><span style="font-size: 15px;background-color: transparent;caret-color: red;color: rgb(96, 96, 96);letter-spacing: 1px;">。(field 指的是 hash 中的 key)field 为锁定的 JVM 进程 + 线程编号的拼接,其中 JVM 进程编号为 UUID 生成。例如说,"xxx:1024"。注意,最后一个冒号后面的数字,为线程编号,</span><span style="font-size: 15px;background-color: transparent;caret-color: red;letter-spacing: 1px;color: rgb(255, 76, 0);">value 为锁定的次数</span><span style="font-size: 15px;background-color: transparent;caret-color: red;color: rgb(96, 96, 96);letter-spacing: 1px;">。因为 Redisson 分布式锁支持可重入性。</span></p>
              </section>
             </section>
             <section style="display: flex;justify-content: flex-end;">
              <section style="width: 13px;height: 13px;background-color: rgb(255, 186, 38);overflow: hidden;">
               <br>
              </section>
             </section>
            </section>
           </section>
          </section>
         </section>
        </section>
        <section style="text-indent: 0em;margin: 24px 8px;line-height: 1.75em;">
         <span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">整体流程:</span>
        </section>
        <ul class="list-paddingleft-1" style="list-style-type: disc;margin-left: 8px;margin-right: 8px;">
         <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
          <section style="text-indent: 0em;margin-top: 24px;margin-bottom: 24px;line-height: 1.75em;">
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">线程去获取锁,获取成功的去</span>
           <span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">执行lua脚本将数据存放到redis中</span>
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,获取失败的</span>
           <span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">while循环自旋尝试去获取锁</span>
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">。</span>
          </section></li>
         <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
          <section style="text-indent: 0em;margin-top: 24px;margin-bottom: 24px;line-height: 1.75em;">
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">使用看</span>
           <span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">门狗机制设置锁的过期时间</span>
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,既可以</span>
           <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">防止突然宕机的死锁又可以将性能提高</span>
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">。</span>
          </section></li>
         <li style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">
          <section style="text-indent: 0em;margin-top: 24px;margin-bottom: 24px;line-height: 1.75em;">
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">使用</span>
           <span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">field的value来实现可重入</span>
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">的状态,</span>
           <span style="font-size: 15px;letter-spacing: 1px;color: rgb(255, 76, 0);">防止同一线程重复加锁导致阻塞等待</span>
           <span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">。</span>
          </section></li>
        </ul>
        <section class="code-snippet__fix code-snippet__js">
         <ul class="code-snippet__line-index code-snippet__js">
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
          
         </ul>
         <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span style="color: rgb(202, 125, 55);">public</span> <span style="color: rgb(202, 125, 55);">void</span> <span style="color: rgb(221, 17, 68);">send</span>() {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;String lockString = <span style="color: rgb(221, 17, 68);">"lock:product:price"</span>;</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);font-style: italic;">// 获取锁对象</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;RLock <span style="color: rgb(202, 125, 55);">lock</span> = redisson.getLock(lockString);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(175, 175, 175);font-style: italic;">// 加锁逻辑</span></span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">lock</span>.<span style="color: rgb(202, 125, 55);">lock</span>();</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">try</span> {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">int</span> stock = Integer.parseInt(stringRedisTemplate.opsForValue().<span style="color: rgb(202, 125, 55);">get</span>(<span style="color: rgb(221, 17, 68);">"stock"</span>));</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">if</span> (stock &gt; <span style="color: rgb(14, 156, 229);">0</span>) {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">int</span> realStock = stock - <span style="color: rgb(14, 156, 229);">1</span>;</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;stringRedisTemplate.opsForValue().<span style="color: rgb(202, 125, 55);">set</span>(<span style="color: rgb(221, 17, 68);">"stock"</span>, realStock + <span style="color: rgb(221, 17, 68);">""</span>);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.<span style="color: rgb(202, 125, 55);">out</span>.println(<span style="color: rgb(221, 17, 68);">"扣减成功,剩余库存:"</span> + realStock);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;} <span style="color: rgb(202, 125, 55);">else</span> {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.<span style="color: rgb(202, 125, 55);">out</span>.println(<span style="color: rgb(221, 17, 68);">"扣减失败,库存不足"</span>);</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;}</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;} <span style="color: rgb(202, 125, 55);">finally</span> {</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(202, 125, 55);">lock</span>.unlock();</span></code><code><span class="code-snippet_outer"> &nbsp; &nbsp;}</span></code><code><span class="code-snippet_outer">}</span></code></pre>
        </section>
       </section>
       <section style="margin: 10px auto;" draggable="true">
        <section style="margin-bottom: -15px;margin-left: 16px;letter-spacing: 1.5px;">
         <span style="color:#7a4442;">源码分析</span>
        </section>
        <section style="display: flex;justify-content: center;align-items: flex-end;">
         <section style="width: 0.886525%;height: 22px;background-color: rgb(66, 163, 225);">
          <br>
         </section>
         <section style="margin-left: 8px;width: 100%;height: 3px;background-color: rgb(255, 238, 194);flex: 1 1 0%;">
          <br>
         </section>
        </section>
       </section>
      </section>
     </section>
    </section>
    
0 1
获取锁逻辑

通过getLock来获取RLock锁,然后调用lock方法来获取锁

            </ul>
            <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">lock</span><span class="code-snippet__params">(<span class="code-snippet__keyword">long</span> leaseTime, TimeUnit unit, <span class="code-snippet__keyword">boolean</span> interruptibly)</span> <span class="code-snippet__keyword">throws</span> InterruptedException </span>{</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">long</span> threadId = Thread.currentThread().getId();</span></code><code><span class="code-snippet_outer">      Long ttl = tryAcquire(leaseTime, unit, threadId);</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__comment">// lock acquired</span></span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">if</span> (ttl == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;订阅频道,当锁线程执行完毕唤起其他线程竞争锁</span></span></code><code><span class="code-snippet_outer">      RFuture&lt;RedissonLockEntry&gt; future = subscribe(threadId);</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">if</span> (interruptibly) {</span></code><code><span class="code-snippet_outer">          commandExecutor.syncSubscriptionInterrupted(future);</span></code><code><span class="code-snippet_outer">      } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">          commandExecutor.syncSubscription(future);</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <span class="code-snippet__comment">// 为获取到锁的线程开始竞争</span></span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">while</span> (<span class="code-snippet__keyword">true</span>) {</span></code><code><span class="code-snippet_outer">              ttl = tryAcquire(leaseTime, unit, threadId);</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__comment">// lock acquired</span></span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">if</span> (ttl == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer">              }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">              <span class="code-snippet__comment">// waiting for message</span></span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">if</span> (ttl &gt;= <span class="code-snippet__number">0</span>) {</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">                      future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">                  } <span class="code-snippet__keyword">catch</span> (InterruptedException e) {</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__keyword">if</span> (interruptibly) {</span></code><code><span class="code-snippet_outer">                          <span class="code-snippet__keyword">throw</span> e;</span></code><code><span class="code-snippet_outer">                      }</span></code><code><span class="code-snippet_outer">                      future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">                  }</span></code><code><span class="code-snippet_outer">              } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">if</span> (interruptibly) {</span></code><code><span class="code-snippet_outer">                      future.getNow().getLatch().acquire();</span></code><code><span class="code-snippet_outer">                  } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">                      future.getNow().getLatch().acquireUninterruptibly();</span></code><code><span class="code-snippet_outer">                  }</span></code><code><span class="code-snippet_outer">              }</span></code><code><span class="code-snippet_outer">          }</span></code><code><span class="code-snippet_outer">      } <span class="code-snippet__keyword">finally</span> {</span></code><code><span class="code-snippet_outer">          unsubscribe(future, threadId);</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">//        get(lockAsync(leaseTime, unit));</span></span></code><code><span class="code-snippet_outer">  }</span></code></pre>
           </section>
           <p style="margin: 24px 8px;line-height: 1.75em;padding-top: 10px;padding-bottom: 15px;letter-spacing: 1.5px;font-size: 14px;color: rgb(51, 51, 51);"><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">主要的加锁逻辑:</span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">通过LUA脚本来实现,保证原子性。</span><br></p>
           <section class="code-snippet__fix code-snippet__js">
            <ul class="code-snippet__line-index code-snippet__js">
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
            </ul>
            <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> &lt;T&gt; RFuture&lt;<span class="code-snippet__built_in">Long</span>&gt; tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (leaseTime != -<span class="code-snippet__number">1</span>) {</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;设定过期时间以及单位不会去续命,默认是30s</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">return</span> tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">    RFuture&lt;<span class="code-snippet__built_in">Long</span>&gt; ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;当加锁逻辑执行完成就会来执行该方法</span></span></code><code><span class="code-snippet_outer">    ttlRemainingFuture.onComplete((ttlRemaining, e) -&gt; {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (e != <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__comment">// lock acquired</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">if</span> (ttlRemaining == <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">            scheduleExpirationRenewal(threadId);</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">    });</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">return</span> ttlRemainingFuture;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> &lt;T&gt; RFuture&lt;T&gt; tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand&lt;T&gt; command) {</span></code><code><span class="code-snippet_outer">      internalLockLeaseTime = unit.toMillis(leaseTime);</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;使用LUA脚本来实现加锁逻辑</span></span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">return</span> evalWriteAsync(getName(), LongCodec.INSTANCE, command,</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"if (redis.call('exists', KEYS[1]) == 0) then "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"redis.call('hincrby', KEYS[1], ARGV[2], 1); "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"redis.call('pexpire', KEYS[1], ARGV[1]); "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"return nil; "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"end; "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"redis.call('hincrby', KEYS[1], ARGV[2], 1); "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"redis.call('pexpire', KEYS[1], ARGV[1]); "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"return nil; "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"end; "</span> +</span></code><code><span class="code-snippet_outer">                      <span class="code-snippet__string">"return redis.call('pttl', KEYS[1]);"</span>,</span></code><code><span class="code-snippet_outer">              Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));</span></code><code><span class="code-snippet_outer">  }</span></code></pre>
           </section>
          </section>
         </section>
         <section>
          <section style="display: flex;justify-content: flex-start;">
           <section>
            <section style="display: flex;justify-content: flex-end;margin-bottom: -8px;">
             <section style="width: 18px;transform: translateX(8px);">
              <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 29.95 28.4" style="display: block;" xml:space="default">
               <g>
                <g>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="22.35" cy="20.8" r="6.6"></circle>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="5.73" cy="5.73" r="4.73"></circle>
                </g>
               </g>
              </svg>
             </section>
            </section>
            <section style="display: flex;justify-content: center;transform-style: preserve-3d;">
             <section style="font-size: 16px;color: rgb(255, 255, 255);background-color: rgb(127, 127, 127);border-radius: 0px 10px;padding: 3px 6px;transform: translateZ(10px);">
              <strong>0</strong>
              <strong data-original-title="" title="">2</strong>
             </section>
             <section style="font-size: 16px;color: rgb(127, 127, 127);text-align: left;padding: 4px 20px;border-radius: 0px 20px 20px 0px;background-color: rgb(239, 248, 255);margin-left: -10px;transform: translateZ(5px);">
              <strong>锁续命逻辑</strong>
             </section>
            </section>
           </section>
          </section>
          <section data-autoskip="1" style="line-height: 1.75em;padding-top: 10px;padding-bottom: 15px;">
           <p style="margin: 24px 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">锁续命时调用</span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">scheduleExpirationRenewal</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;"><span style="color: rgb(96, 96, 96);font-size: 15px;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;letter-spacing: 1.5px;text-align: left;white-space-collapse: preserve;background-color: rgb(250, 250, 250);">方法来实现,只要利用的是Timeout做成一个定时循环调用</span></span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">renewExiration</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;"><span style="color: rgb(96, 96, 96);font-size: 15px;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;letter-spacing: 1.5px;text-align: left;white-space-collapse: preserve;background-color: rgb(250, 250, 250);">方法,利用</span></span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">lua脚本10秒进行检查一下</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;"><span style="color: rgb(96, 96, 96);font-size: 15px;font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;letter-spacing: 1.5px;text-align: left;white-space-collapse: preserve;background-color: rgb(250, 250, 250);">。</span></span></p>
           <section class="code-snippet__fix code-snippet__js">
            <ul class="code-snippet__line-index code-snippet__js">
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
            </ul>
            <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> void renewExpiration() {</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;使用currentHashMap进行缓存</span></span></code><code><span class="code-snippet_outer">    ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.<span class="code-snippet__keyword">get</span>(getEntryName());</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (ee == <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;定时任务去执行renewExpiration方法</span></span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;&nbsp;internalLockLeaseTime默认值为30s,10s执行</span></span></code><code><span class="code-snippet_outer">    Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__meta">@Override</span></span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">public</span> void run(Timeout timeout) throws Exception {</span></code><code><span class="code-snippet_outer">            ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.<span class="code-snippet__keyword">get</span>(getEntryName());</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (ent == <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__built_in">Long</span> threadId = ent.getFirstThreadId();</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (threadId == <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">// 执行lua脚本进行检查</span></span></code><code><span class="code-snippet_outer">            RFuture&lt;<span class="code-snippet__built_in">Boolean</span>&gt; future = renewExpirationAsync(threadId);</span></code><code><span class="code-snippet_outer">            future.onComplete((res, e) -&gt; {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">if</span> (e != <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">                    log.error(<span class="code-snippet__string">"Can't update lock "</span> + getName() + <span class="code-snippet__string">" expiration"</span>, e);</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__keyword">return</span>;</span></code><code><span class="code-snippet_outer">                }</span></code><code><span class="code-snippet_outer">                </span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">if</span> (res) {</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__comment">// reschedule itself</span></span></code><code><span class="code-snippet_outer">                    renewExpiration();</span></code><code><span class="code-snippet_outer">                }</span></code><code><span class="code-snippet_outer">            });</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">    }, internalLockLeaseTime / <span class="code-snippet__number">3</span>, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">    </span></code><code><span class="code-snippet_outer">    ee.setTimeout(task);</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">protected</span> RFuture&lt;<span class="code-snippet__built_in">Boolean</span>&gt; renewExpirationAsync(long threadId) {</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">return</span> evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__string">"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then "</span> +</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__string">"redis.call('pexpire', KEYS[1], ARGV[1]); "</span> +</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__string">"return 1; "</span> +</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__string">"end; "</span> +</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__string">"return 0;"</span>,</span></code><code><span class="code-snippet_outer">            Collections.singletonList(getName()),</span></code><code><span class="code-snippet_outer">            internalLockLeaseTime, getLockName(threadId));</span></code><code><span class="code-snippet_outer">}</span></code></pre>
           </section>
           <p><span style="color: rgb(51, 51, 51);font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;font-size: 14px;letter-spacing: 1.5px;text-align: left;white-space-collapse: preserve;background-color: rgb(250, 250, 250);"></span></p>
          </section>
         </section>
         <section>
          <section style="display: flex;justify-content: flex-start;">
           <section>
            <section style="display: flex;justify-content: flex-end;margin-bottom: -8px;">
             <section style="width: 18px;transform: translateX(8px);">
              <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 29.95 28.4" style="display: block;" xml:space="default">
               <g>
                <g>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="22.35" cy="20.8" r="6.6"></circle>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="5.73" cy="5.73" r="4.73"></circle>
                </g>
               </g>
              </svg>
             </section>
            </section>
            <section style="display: flex;justify-content: center;transform-style: preserve-3d;">
             <section style="font-size: 16px;color: rgb(255, 255, 255);background-color: rgb(127, 127, 127);border-radius: 0px 10px;padding: 3px 6px;transform: translateZ(10px);">
              <strong>0</strong>
              <strong data-original-title="" title="">3</strong>
             </section>
             <section style="font-size: 16px;color: rgb(127, 127, 127);text-align: left;padding: 4px 20px;border-radius: 0px 20px 20px 0px;background-color: rgb(239, 248, 255);margin-left: -10px;transform: translateZ(5px);">
              <strong>锁自旋逻辑</strong>
             </section>
            </section>
           </section>
          </section>
          <section data-autoskip="1" style="line-height: 1.75em;padding-top: 10px;padding-bottom: 15px;">
           <p style="margin: 24px 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">在获取锁逻辑当中,当某个线程获取到锁之后,返回出来的</span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">ttl就是该线程剩余时间</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,抢锁线程订阅频道,当锁中线程执行完成唤醒等待线程去竞争锁,使用</span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">while循环去等待剩余时间</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,然后去尝试获取锁。</span><br></p>
           <section class="code-snippet__fix code-snippet__js">
            <ul class="code-snippet__line-index code-snippet__js">
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
            </ul>
            <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">// 抢锁线程订阅频道,当锁中线程执行完成唤醒等待线程去竞争锁</span></span></code><code><span class="code-snippet_outer">    RFuture&lt;RedissonLockEntry&gt; future = subscribe(threadId);</span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">if</span> (interruptibly) {</span></code><code><span class="code-snippet_outer">        commandExecutor.syncSubscriptionInterrupted(future);</span></code><code><span class="code-snippet_outer">    } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">        commandExecutor.syncSubscription(future);</span></code><code><span class="code-snippet_outer">    }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">    <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">        <span class="code-snippet__keyword">while</span> (<span class="code-snippet__literal">true</span>) {</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;再次尝试获取锁</span></span></code><code><span class="code-snippet_outer">            ttl = tryAcquire(leaseTime, unit, threadId);</span></code><code><span class="code-snippet_outer">            <span class="code-snippet__comment">// lock acquired</span></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (ttl == <span class="code-snippet__literal">null</span>) {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">break</span>;</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__comment">// waiting for message</span></span></code><code><span class="code-snippet_outer">            <span class="code-snippet__keyword">if</span> (ttl &gt;= <span class="code-snippet__number">0</span>) {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">// 获取信号量执行tryAcquire() 简单理解为等待剩余时间</span></span></code><code><span class="code-snippet_outer">                    future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">                } <span class="code-snippet__keyword">catch</span> (InterruptedException e) {</span></code><code><span class="code-snippet_outer">                    <span class="code-snippet__keyword">if</span> (interruptibly) {</span></code><code><span class="code-snippet_outer">                        <span class="code-snippet__keyword">throw</span> e;</span></code><code><span class="code-snippet_outer">                    }</span></code><code><span class="code-snippet_outer">                    future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">                }</span></code><code><span class="code-snippet_outer">            } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">                <span class="code-snippet__keyword">if</span> (interruptibly) {</span></code><code><span class="code-snippet_outer">                    future.getNow().getLatch().acquire();</span></code><code><span class="code-snippet_outer">                } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">                    future.getNow().getLatch().acquireUninterruptibly();</span></code><code><span class="code-snippet_outer">                }</span></code><code><span class="code-snippet_outer">            }</span></code><code><span class="code-snippet_outer">        }</span></code><code><span class="code-snippet_outer">    } <span class="code-snippet__keyword">finally</span> {</span></code><code><span class="code-snippet_outer">        unsubscribe(future, threadId);</span></code><code><span class="code-snippet_outer">    }</span></code></pre>
           </section>
          </section>
         </section>
         <section>
          <section style="display: flex;justify-content: flex-start;">
           <section>
            <section style="display: flex;justify-content: flex-end;margin-bottom: -8px;">
             <section style="width: 18px;transform: translateX(8px);">
              <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 29.95 28.4" style="display: block;" xml:space="default">
               <g>
                <g>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="22.35" cy="20.8" r="6.6"></circle>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="5.73" cy="5.73" r="4.73"></circle>
                </g>
               </g>
              </svg>
             </section>
            </section>
            <section style="display: flex;justify-content: center;transform-style: preserve-3d;">
             <section style="font-size: 16px;color: rgb(255, 255, 255);background-color: rgb(127, 127, 127);border-radius: 0px 10px;padding: 3px 6px;transform: translateZ(10px);">
              <strong>04</strong>
             </section>
             <section style="font-size: 16px;color: rgb(127, 127, 127);text-align: left;padding: 4px 20px;border-radius: 0px 20px 20px 0px;background-color: rgb(239, 248, 255);margin-left: -10px;transform: translateZ(5px);">
              <strong>重入锁逻辑</strong>
             </section>
            </section>
           </section>
          </section>
          <section data-autoskip="1" style="line-height: 1.75em;padding-top: 10px;padding-bottom: 15px;">
           <p style="margin: 24px 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">在加锁的时候,</span><span style="letter-spacing: 1px;color: rgb(61, 170, 214);font-size: 16px;">执行Lua脚本去判断该线程是否存在</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,如果存在则将key相关field的</span><span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">value加上1</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,设置过期时间达到一个重入的效果。</span><br></p>
           <section class="code-snippet__fix code-snippet__js">
            <ul class="code-snippet__line-index code-snippet__js">
             
             
             
             
             
             
             
             
             
             
             
             
             
            </ul>
            <pre class="code-snippet__js" data-lang="bash"><code><span class="code-snippet_outer"><span class="code-snippet__built_in">return</span> evalWriteAsync(getName(), LongCodec.INSTANCE, <span class="code-snippet__built_in">command</span>,</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__string">"if (redis.call('exists', KEYS[1]) == 0) then "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"redis.call('hincrby', KEYS[1], ARGV[2], 1); "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"redis.call('pexpire', KEYS[1], ARGV[1]); "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"return nil; "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"end; "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"redis.call('hincrby', KEYS[1], ARGV[2], 1); "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"redis.call('pexpire', KEYS[1], ARGV[1]); "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"return nil; "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"end; "</span> +</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__string">"return redis.call('pttl', KEYS[1]);"</span>,</span></code><code><span class="code-snippet_outer">      Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));</span></code></pre>
           </section>
          </section>
         </section>
         <section>
          <section style="display: flex;justify-content: flex-start;">
           <section>
            <section style="display: flex;justify-content: flex-end;margin-bottom: -8px;">
             <section style="width: 18px;transform: translateX(8px);">
              <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 29.95 28.4" style="display: block;" xml:space="default">
               <g>
                <g>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="22.35" cy="20.8" r="6.6"></circle>
                 <circle style="fill:none;stroke:#b7eea6;stroke-miterlimit:10;stroke-width:2px;" cx="5.73" cy="5.73" r="4.73"></circle>
                </g>
               </g>
              </svg>
             </section>
            </section>
            <section style="display: flex;justify-content: center;transform-style: preserve-3d;">
             <section style="font-size: 16px;color: rgb(255, 255, 255);background-color: rgb(127, 127, 127);border-radius: 0px 10px;padding: 3px 6px;transform: translateZ(10px);">
              <strong>05</strong>
             </section>
             <section style="font-size: 16px;color: rgb(127, 127, 127);text-align: left;padding: 4px 20px;border-radius: 0px 20px 20px 0px;background-color: rgb(239, 248, 255);margin-left: -10px;transform: translateZ(5px);">
              <strong>独占锁获取逻辑</strong>
             </section>
            </section>
           </section>
          </section>
          <section data-autoskip="1" style="line-height: 1.75em;padding-top: 10px;padding-bottom: 15px;">
           <p style="margin: 24px 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">为了满足特殊要求下的业务,比如说需要实现</span><span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">对共享资源的互斥访问</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,避免</span><span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">多个节点同时修改某一值</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">,</span><span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">避免死锁避免线程等</span><span style="letter-spacing: 1px;font-size: 16px;color: rgb(61, 170, 214);">待</span><span style="font-size: 15px;color: rgb(96, 96, 96);letter-spacing: 1px;">等问题,Redisson还提供一个独占锁的效果。</span></p>
           <section class="code-snippet__fix code-snippet__js">
            <ul class="code-snippet__line-index code-snippet__js">
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
             
            </ul>
            <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">&nbsp; waitTime:表示等待时间</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">&nbsp;&nbsp;leaseTime: 获取锁的过期时间</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">&nbsp;&nbsp;TimeUnit: 单位</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">*/</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">boolean</span> <span class="code-snippet__title">tryLock</span><span class="code-snippet__params">(<span class="code-snippet__keyword">long</span> waitTime, <span class="code-snippet__keyword">long</span> leaseTime, TimeUnit unit)</span> <span class="code-snippet__keyword">throws</span> InterruptedException </span>{</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">long</span> time = unit.toMillis(waitTime);</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">long</span> current = System.currentTimeMillis();</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">long</span> threadId = Thread.currentThread().getId();</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;尝试去加锁</span></span></code><code><span class="code-snippet_outer">      Long ttl = tryAcquire(leaseTime, unit, threadId);</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__comment">// lock acquired</span></span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">if</span> (ttl == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">true</span>;</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer">      </span></code><code><span class="code-snippet_outer">      time -= System.currentTimeMillis() - current;</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;时间过了加锁失败直接return false</span></span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="code-snippet__keyword">if</span>&nbsp;(time&nbsp;&lt;=&nbsp;<span class="code-snippet__number">0</span>)&nbsp;{</span></code><code><span class="code-snippet_outer">          acquireFailed(threadId);</span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">false</span>;</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="code-snippet__comment">//&nbsp;等待时长</span></span></code><code><span class="code-snippet_outer">      current = System.currentTimeMillis();</span></code><code><span class="code-snippet_outer">      RFuture&lt;RedissonLockEntry&gt; subscribeFuture = subscribe(threadId);</span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">if</span> (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {</span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">if</span> (!subscribeFuture.cancel(<span class="code-snippet__keyword">false</span>)) {</span></code><code><span class="code-snippet_outer">              subscribeFuture.onComplete((res, e) -&gt; {</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">if</span> (e == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer">                      unsubscribe(subscribeFuture, threadId);</span></code><code><span class="code-snippet_outer">                  }</span></code><code><span class="code-snippet_outer">              });</span></code><code><span class="code-snippet_outer">          }</span></code><code><span class="code-snippet_outer">          acquireFailed(threadId);</span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">false</span>;</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">      <span class="code-snippet__keyword">try</span> {</span></code><code><span class="code-snippet_outer">          time -= System.currentTimeMillis() - current;</span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">if</span> (time &lt;= <span class="code-snippet__number">0</span>) {</span></code><code><span class="code-snippet_outer">              acquireFailed(threadId);</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">false</span>;</span></code><code><span class="code-snippet_outer">          }</span></code><code><span class="code-snippet_outer">      </span></code><code><span class="code-snippet_outer">          <span class="code-snippet__keyword">while</span> (<span class="code-snippet__keyword">true</span>) {</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">long</span> currentTime = System.currentTimeMillis();</span></code><code><span class="code-snippet_outer">              ttl = tryAcquire(leaseTime, unit, threadId);</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__comment">// lock acquired</span></span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">if</span> (ttl == <span class="code-snippet__keyword">null</span>) {</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">true</span>;</span></code><code><span class="code-snippet_outer">              }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">              time -= System.currentTimeMillis() - currentTime;</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">if</span> (time &lt;= <span class="code-snippet__number">0</span>) {</span></code><code><span class="code-snippet_outer">                  acquireFailed(threadId);</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">false</span>;</span></code><code><span class="code-snippet_outer">              }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">              <span class="code-snippet__comment">// waiting for message</span></span></code><code><span class="code-snippet_outer">              currentTime = System.currentTimeMillis();</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">if</span> (ttl &gt;= <span class="code-snippet__number">0</span> &amp;&amp; ttl &lt; time) {</span></code><code><span class="code-snippet_outer">                  subscribeFuture.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">              } <span class="code-snippet__keyword">else</span> {</span></code><code><span class="code-snippet_outer">                  subscribeFuture.getNow().getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);</span></code><code><span class="code-snippet_outer">              }</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">              time -= System.currentTimeMillis() - currentTime;</span></code><code><span class="code-snippet_outer">              <span class="code-snippet__keyword">if</span> (time &lt;= <span class="code-snippet__number">0</span>) {</span></code><code><span class="code-snippet_outer">                  acquireFailed(threadId);</span></code><code><span class="code-snippet_outer">                  <span class="code-snippet__keyword">return</span> <span class="code-snippet__keyword">false</span>;</span></code><code><span class="code-snippet_outer">              }</span></code><code><span class="code-snippet_outer">          }</span></code><code><span class="code-snippet_outer">      } <span class="code-snippet__keyword">finally</span> {</span></code><code><span class="code-snippet_outer">          unsubscribe(subscribeFuture, threadId);</span></code><code><span class="code-snippet_outer">      }</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">//        return get(tryLockAsync(waitTime, leaseTime, unit));</span></span></code><code><span class="code-snippet_outer">  }</span></code></pre>
           </section>
          </section>
         </section>
        </section>
       </section>
       <p><span style="color: rgb(53, 53, 53);font-family: MicrosoftYaHei, 微软雅黑;font-size: 0px;letter-spacing: normal;text-align: start;text-wrap: wrap;background-color: rgba(0, 0, 0, 0.5);">http://xm.shop0025.cn/tKpp7r</span></p>
      </section>
     </section>
    </section>
    

文章有帮助的话,   点赞在看转发吧。

一起讨论,谢谢支持哟



长按二维码关注我
每日 分享干货