深入理解ReentrantLock:尝试性获取锁的源码剖析
最编程
2024-07-28 18:16:08
...
ReentrantLock的tryLock方法是对Lock接口的tryLock实现
应用场景
非阻塞的场景,允许某些任务不执行(比如防止重复提交业务),或超时不执行(比如防止资源等待队列溢出)等
不带参数的 tryLock
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
实现比较简单,内部调用sync#nonfairTryAcquire方法,该方法前篇分析lock方法的时候已经解析过了在此不做赘述
带超时和支持中断响应的 tryLock
/**
* Acquires the lock if it is free within the given waiting time and the
* current thread has not been {@linkplain Thread#interrupt interrupted}.
*(在指定的时间内获取锁如果锁未被其他线程持有,并且这个线程没有被中断)
* <p>If the lock is available this method returns immediately
* with the value {@code true}.
*(如果锁是可用的这个方法会立刻返回true)
* If the lock is not available then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until one of three things happens:
* (如果锁是不可用的那么当前线程将不可用对于线程调度,并且会休眠直到1件或3件事情发生)
* <ul>
* <li>The lock is acquired by the current thread; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the
* current thread, and interruption of lock acquisition is supported; or
* <li>The specified waiting time elapses
* </ul>
*(这个锁被当前线程持有;或者其他的线程中断了当前线程,并且锁的中断是被支持的;或者指定的等待时间超时)
* <p>If the lock is acquired then the value {@code true} is returned.
*(如果这个锁被获取那么将返回true)
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while acquiring
* the lock, and interruption of lock acquisition is supported,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
* 如果线程被中断将抛出InterruptedException异常
* <p>If the specified waiting time elapses then the value {@code false}
* is returned.
* If the time is
* less than or equal to zero, the method will not wait at all.
*(如果指定的等待时间到了还未获取到锁将返回false,如果指定的时间少于或者等于0,方法将不会等待)
* <p><b>Implementation Considerations</b>
*(实现的注意事项)
* <p>The ability to interrupt a lock acquisition in some implementations
* may not be possible, and if possible may
* be an expensive operation.
* The programmer should be aware that this may be the case. An
* implementation should document when this is the case.
*(在某些实现中中断锁获取的能力可能不可能,并且可能的话是一个昂贵的操作。程序员应该意识到情况可能是这样的。一个在这种情况下,实现应该记录下来。)
* <p>An implementation can favor responding to an interrupt over normal
* method return, or reporting a timeout.
*(一个实现可以响应一个中断,或者报告超时)
* <p>A {@code Lock} implementation may be able to detect
* erroneous use of the lock, such as an invocation that would cause
* deadlock, and may throw an (unchecked) exception in such circumstances.
* The circumstances and the exception type must be documented by that
* {@code Lock} implementation.
*(实现可能会检测到锁的错误使用,例如可能导致死锁的调用,并可能在这种情况下引发(未经检查的)异常。这种情况和异常类型必须由{@code lock}实现记录)
* @param time the maximum time to wait for the lock (获取锁的最大等待时间)
* @param unit the time unit of the {@code time} argument (时间单位)
* @return {@code true} if the lock was acquired and {@code false}
* if the waiting time elapsed before the lock was acquired
*(如果锁被获取了返回true,如果等待时间超时还未获取则返回false)
* @throws InterruptedException if the current thread is interrupted
* while acquiring the lock (and interruption of lock
* acquisition is supported)
*(当前线程被中断了需要返回InterruptedException当获取锁的时候(并且锁的获取中断是被支持的))
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
查看ReentrantLock的实现
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
sync#tryAcquireNanos 调用的是父类AbstractQueuedSynchronizer的tryAcquireNanos方法
/**
* Attempts to acquire in exclusive mode, aborting if interrupted,
* and failing if the given timeout elapses. Implemented by first
* checking interrupt status, then invoking at least once {@link
* #tryAcquire}, returning on success. Otherwise, the thread is
* queued, possibly repeatedly blocking and unblocking, invoking
* {@link #tryAcquire} until success or the thread is interrupted
* or the timeout elapses. This method can be used to implement
* method {@link Lock#tryLock(long, TimeUnit)}.
*
* @param arg the acquire argument. This value is conveyed to
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
* @param nanosTimeout the maximum number of nanoseconds to wait
* @return {@code true} if acquired; {@code false} if timed out
* @throws InterruptedException if the current thread is interrupted
*/
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
//中断检测
if (Thread.interrupted())
throw new InterruptedException();
//step1. 调用tryAcquire先尝试获取锁,如果失败则调用doAcquireNanos
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
AbstractQueuedSynchronizer#doAcquireNanos
/**
* Acquires in exclusive timed mode.
*
* @param arg the acquire argument
* @param nanosTimeout max wait time
* @return {@code true} if acquired
*/
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
//计算出到期时间
final long deadline = System.nanoTime() + nanosTimeout;
//新增独占节点
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
//反复重试直到成功获取锁或者超时返回false
for (;;) {
final Node p = node.predecessor();
//该节点的前节点是头节点则尝试获取锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
//剩余时间
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
//超时返回false
return false;
//shouldParkAfterFailedAcquire 判断是否需要阻塞线程 并且剩余时间大于 spinForTimeoutThreshold (默认1000)
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
//中断检测
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
原文地址:https://www.cnblogs.com/lomoye/p/12699238.html
推荐阅读
-
深入理解Java源码:ReentrantLock的lockInterruptibly与tryLock方法剖析
-
剖析Redisson分布式锁(第一部分):深入理解RedissonLock.tryLock的实现代码
-
深入理解Java AQS中的ReentrantLock锁:构造与源码剖析
-
深入剖析Redisson Lock的分布式锁实现机制与源码解读
-
深入理解ReentrantLock:尝试性获取锁的源码剖析
-
【2022新手指南】Java编程进阶之路 - 六、技术架构篇 ### MySQL索引底层解析与优化实战 - 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少? - Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理 - Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开 - Zookeeper是个啥?特性和应用场景大公开 - ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节 - 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用 - Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位 - RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略 - 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南 - RocketMQ特性和应用场景揭示:理解其精髓与差异化优势 - Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析 - ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用 - MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学 - BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用 - Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析 - 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示 - 解密Netty粘包与拆包现象,怎样有效应对这一常见问题 - 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术 - Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处 - Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现 ----------------------- 七、结语与回顾
-
深入展示一种可以理解 Java 锁机制、Synchronized 和 ReentrantLock 的方法
-
深入理解Spring源码:启动过程完结篇——启动完成后的行为剖析
-
深入理解Spring源码:ContextLoaderListener的初始化过程剖析
-
深入理解 SpringBoot 中的 @Value 注解源码剖析