ReentrantLock总结
简述
【ReentrantLock总结】ReentrantLock是java中非常重要的一个并发工具,相比于java原生的synchronized有着更好的性能
## 概念速查
ReentrantLock涉及的名称和概念较多,这里做一个简单的归类和解释,具体更为详细的内容,请自行Baidu或Google,这部分用于在阅读文章的时候,快速了解一些名称的概念,如果已经熟悉,请跳过。
快速预览 更强大的功能,玩玩意味着更为复杂的使用,ReentrankLock的使用比起synchronize,多了一个主动释放锁的代码,一个典型的使用示例如下
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
// ... method body
}finally {
lock.unlock();
}
注意unlock的操作一定要置于finally块中,这样才能保证锁一定能释放。
uml图 看完了简单的使用示例,我们来快速的看一遍ReentrankLock的结构,下面是用idea的工具快速生成的uml图,感谢idea,大大提高了我们的工作质量。
文章图片
ReentrantLock-UML.png 一次性过于深入的讨论,往往会迷失在繁琐的细节中,而难以把握全貌,而细节往往是由全局的目标决定的,所以我们一层一层的谈,不一次性深入最终代码。
由uml图,我们可以看出,ReentrantLock类是一个Lock接口的具体实现,每个ReentrantLock的实例,都持有一个sync对象,且这个sync是final修饰的,这个sync有两种具体的子类,分别是NonfairSync和FairSync,也就是非公平锁和公平锁。
ReentrantLock有两个构造方法,我们可以先看这两个方法,
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = (fair)? new FairSync() : new NonfairSync();
}
可以看出,所谓构造函数,其实就是初始化需要使用的sync的类型,默认是非公平锁。参考公平锁与非公平锁
简要的预备知识 CAS
ReentrantLock的核心是对CAS方法的使用,现代的CPU提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 compareAndSet()使用了这些命令,具体请查阅CAS原理分析
wait
第一层解析 加锁部分
ReentrantLock的lock其实就是调用具体的sync的lock方法。
公平锁和非公平锁的加锁是有所不同的
对于公平锁来说如下
final void lock() {
acquire(1);
}
对于非公平锁来说,是如下的
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
elseacquire(1);
}
很显然,我们可以看出对于公平锁来说,非公平锁多了一个操作。我们首先来解释一下compareAndSetState方法,这个方法来自于sync继承的AbstractQueuedSynchronizer父类。state为0表示当前锁没有被占用,如果大于0,则表示被持有了,使用compareAndSetState,底层是个CAS方法,如果锁没有被占用,则置为占用状态,并且通过setExclusiveOwnerThread,将当前线程设置为该锁的持有者。
tryAcquire这个方法的作用,java的官方注释上如下写到
Acquires in exclusive mode, ignoring interrupts
大意是"尝试在独占模式下获取,忽略中断"。
截止到目前为止,我们看到的加锁过程的流程图如下,很简单
文章图片
ReentrantLock第一层.png acquire的工作 接下来,我们研究一下acquire做的工作
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire,尝试将锁的状态置为arg,如果成功,则结束function,如果失败,在CHL队列中添加一个新的独占锁的节点,节点如果添加失败,则不做后续处理,如果成功则使用selfInterrupt将当前线程中断。流程图如下
解锁部分
我们跳过acquire具体做了什么,我们直接来看unlock做了什么。
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
推荐阅读
- 7.9号工作总结~司硕
- 最有效的时间管理工具(赢效率手册和总结笔记)
- Swift中willSet和didSet的简述
- 数据库总结语句
- 周总结|周总结 感悟
- 周总结43
- 参加【21天写作挑战赛】,第七期第14天,挑战感受小总结
- 第二阶段day1总结
- 新梦想91期特训班两天一晚学习感想及总结(学生(魏森林))
- 周总结(10.5-10.11)