架构系列——通过ReentrantLock源码分析给对象上锁的原理
作者专注于Java、架构、Linux、小程序、爬虫、自动化等技术。 工作期间含泪整理出一些资料,微信搜索【javaUp】,回复 【java】【黑客】【爬虫】【小程序】【面试】等关键字免费获取资料。
目录
一、整体结构
该类位于java.util.concurrent.locks包下
首先看一下结构:
ReentrantLock中:
3个类:Sync、NonfairSync、FairSync
若干个方法:lock()、tryLock()、unlock()、acquireInterruptibly(int arg)等
具体流程
二、三个内部类
1.Sync
2.NonfairSync
3.FairSync
三、主要方法
注:流程图省略了其他相关类的一些方法,只讲ReentrantLock类里面的方法,比如AQS(AbstractQueuedSynchronizer)类里面的acquere方法中省略了acquireQueued()和selfInterrupt()。
如果tryAcquire(arg)返回成功,则说明当前线程成功获取了锁(第一次获取或者重入),由取反和&&可知,整个流程到这结束,只有当前线程获取锁失败才会执行后面的判断。addWaiter(Node.EXCLUSIVE)
部分代码描述了当线程获取锁失败时如何安全的加入同步等待队列。这部分代码可以说是整个加锁流程源码的精华,充分体现了并发编程的艺术性。
1.lock()方法
1.1 如果该lock是NonfairSync类的实例,则进入NonfairSync的lock()里:
最底层还是进入nonfairTryAcquire()方法里
1.2 如果该lock是FairSync类的实例,则进入FairSync的lock()里:
最底层是进入tryAcquire()方法里
2.tryLock()方法
一步到位,直接调用nonfairTryAcquire()方法
3.unlock()方法
4.lockInterruptibly()方法
这是Lock锁和synchronized锁相比独有的特性之一,获取锁的线程是可以被中断的,而且中断的时候抛出异常;
四、其它
由上面的图可知,ReentrantLock里面的最最基本的方法是tryAcquire()、nonfairTryAcquire()和tryRelease()
把这两个方法搞懂了,这个类也就明白很大一部分了
另外要理解两点:
1.公平锁与非公平锁的区别
FairSync中整个tryAcquire()代码只比nonfairTryAcquire()方法多了这么一行!!!
主要判断:是否有其它线程在队列的最前面。
以此来保证有序性,也就是先来后到!
这就是公平!
而不公平就是可以插队拿到锁!
2.重入锁的实现原理
1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功;
2. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功