作者:微信小助手
发布时间:2023-10-23T09:53:05
STRAT 乘风破浪 | 直挂云帆 Redisson是基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。能够为我们提供多服务版并发解决的能力,大大降低分布式系统的难度。
主要的使用时集成到Springboot中,首先引入pom依赖,然后引入配置。 通过getLock来获取RLock锁,然后调用lock方法来获取锁。 文章有帮助的话, 点赞、在看、转发吧。 一起讨论,谢谢支持哟
</ul>
<pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><dependency></span></code><code><span class="code-snippet_outer"> <groupId>org.redisson</groupId></span></code><code><span class="code-snippet_outer"> <artifactId>redisson</artifactId></span></code><code><span class="code-snippet_outer"> <version>3.11.1</version></span></code><code><span class="code-snippet_outer"></dependency></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"> <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"> <span style="color: rgb(202, 125, 55);">private</span> String host;</span></code><code><span class="code-snippet_outer"> <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"> <span style="color: rgb(202, 125, 55);">private</span> String port;</span></code><code><span class="code-snippet_outer"> <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"> <span style="color: rgb(202, 125, 55);">private</span> String password;</span></code><code><span class="code-snippet_outer"> <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"> <span style="color: rgb(202, 125, 55);">private</span> int database;</span></code><code><span class="code-snippet_outer"> <span style="color: rgb(175, 175, 175);">@Bean</span></span></code><code><span class="code-snippet_outer"> <span style="color: rgb(202, 125, 55);">public</span> RedissonClient getRedisson() {</span></code><code><span class="code-snippet_outer"> Config config = new Config();</span></code><code><span class="code-snippet_outer"> <span style="color: rgb(175, 175, 175);font-style: italic;">//线程定时间隔时间10s</span></span></code><code><span class="code-snippet_outer"> config.setLockWatchdogTimeout(<span style="color: rgb(14, 156, 229);">10000</span>);</span></code><code><span class="code-snippet_outer"> <span style="color: rgb(175, 175, 175);font-style: italic;">//设置单机版本redis</span></span></code><code><span class="code-snippet_outer"> 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"> <span style="color: rgb(175, 175, 175);font-style: italic;">//设置集群的方式</span></span></code><code><span class="code-snippet_outer"> 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"> <span style="color: rgb(175, 175, 175);font-style: italic;">//添加主从配置</span></span></code><code><span class="code-snippet_outer"> 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"> <span style="color: rgb(202, 125, 55);">return</span> Redisson.create(config);</span></code><code><span class="code-snippet_outer"> }</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: 微软雅黑, "Microsoft YaHei", 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"> String lockString = <span style="color: rgb(221, 17, 68);">"lock:product:price"</span>;</span></code><code><span class="code-snippet_outer"> <span style="color: rgb(175, 175, 175);font-style: italic;">// 获取锁对象</span></span></code><code><span class="code-snippet_outer"> RLock <span style="color: rgb(202, 125, 55);">lock</span> = redisson.getLock(lockString);</span></code><code><span class="code-snippet_outer"> <span style="color: rgb(175, 175, 175);font-style: italic;">// 加锁逻辑</span></span></code><code><span class="code-snippet_outer"> <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"> <span style="color: rgb(202, 125, 55);">try</span> {</span></code><code><span class="code-snippet_outer"> <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"> <span style="color: rgb(202, 125, 55);">if</span> (stock > <span style="color: rgb(14, 156, 229);">0</span>) {</span></code><code><span class="code-snippet_outer"> <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"> 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"> 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"> } <span style="color: rgb(202, 125, 55);">else</span> {</span></code><code><span class="code-snippet_outer"> 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"> }</span></code><code><span class="code-snippet_outer"> } <span style="color: rgb(202, 125, 55);">finally</span> {</span></code><code><span class="code-snippet_outer"> <span style="color: rgb(202, 125, 55);">lock</span>.unlock();</span></code><code><span class="code-snippet_outer"> }</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>
</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"> <span class="code-snippet__comment">// 订阅频道,当锁线程执行完毕唤起其他线程竞争锁</span></span></code><code><span class="code-snippet_outer"> RFuture<RedissonLockEntry> 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__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 >= <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> <T> RFuture<<span class="code-snippet__built_in">Long</span>> 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"> <span class="code-snippet__comment">// 设定过期时间以及单位不会去续命,默认是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<<span class="code-snippet__built_in">Long</span>> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 当加锁逻辑执行完成就会来执行该方法</span></span></code><code><span class="code-snippet_outer"> ttlRemainingFuture.onComplete((ttlRemaining, e) -> {</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"> }</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"> <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {</span></code><code><span class="code-snippet_outer"> internalLockLeaseTime = unit.toMillis(leaseTime);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 使用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, "Liberation Mono", 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, "Liberation Mono", 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, "Liberation Mono", 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"> <span class="code-snippet__comment">// 使用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"> <span class="code-snippet__comment">// 定时任务去执行renewExpiration方法</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 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"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">// 执行lua脚本进行检查</span></span></code><code><span class="code-snippet_outer"> RFuture<<span class="code-snippet__built_in">Boolean</span>> future = renewExpirationAsync(threadId);</span></code><code><span class="code-snippet_outer"> future.onComplete((res, e) -> {</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<<span class="code-snippet__built_in">Boolean</span>> 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, "Liberation Mono", 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"> <span class="code-snippet__comment">// 抢锁线程订阅频道,当锁中线程执行完成唤醒等待线程去竞争锁</span></span></code><code><span class="code-snippet_outer"> RFuture<RedissonLockEntry> 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"> <span class="code-snippet__comment">// 再次尝试获取锁</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 >= <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"> <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"> waitTime:表示等待时间</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> leaseTime: 获取锁的过期时间</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> 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"> <span class="code-snippet__comment">// 尝试去加锁</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"> <span class="code-snippet__comment">// 时间过了加锁失败直接return false</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (time <= <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 class="code-snippet__comment">// 等待时长</span></span></code><code><span class="code-snippet_outer"> current = System.currentTimeMillis();</span></code><code><span class="code-snippet_outer"> RFuture<RedissonLockEntry> 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) -> {</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 <= <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 <= <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 >= <span class="code-snippet__number">0</span> && ttl < 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 <= <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>