ReentrantLock源码分析
Posted codeHorde
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock源码分析相关的知识,希望对你有一定的参考价值。
首先看看ReentrantLock类结构。
可以看到三个内部类,一个抽象类Sync,一个是NonfairSync,一个是FairSync。ReentrantLock的lock方法也是调用了sync的lock方法。
sync类继承了AbstractQueuedSynchronizer类,后面简称为AQS,这个类也是核心所在。这里先分析FairSync的实现,公平锁分析完了,非公平锁就一个地方不一样。
可以看到子类主要重写了lock和tryAcquire方法。lock是sync的方法,tryAcquire方法是AQS的方法,都是抽象的,由子类去实现。所以自己想实现一个锁就可以继承AQS重写tryAcquire方法。
lock方法灰调用acquire方法,acquire方法由AQS实现。aquire方法中比较重要的是tryAcquire方法获取锁逻辑(由子类实现),acquireQueued()自己实现
先是获取锁,成功直接返回,失败则会创建一个节点加入到队列中去。
下面直接到FairSync的tryAcqure方法
获取当前状态,0代表未加锁,非0代表未加锁。如果为0,先判断队列中是否存在线程等待,没有等待则CAS去获取锁,获取锁成功后设置当前线程占用锁,返回。如果不是0,再判断持有锁的线程是否是当前线程,这里就是判断是否可重入,重入一次状态加1。
当tryAcquire返回false,就会向下面走先调addWaiter() 封装节点。先贴一张节点类图。Node中最重要的就是几个状态
addwaiter方法进来先判断tail节点是不是为空,因为head和tail都是延迟加载的,所以第一次肯定为null,则进入enq方法,如果不为null,则设置当前节点为尾节点。
自旋设置tail节点。第一次进来肯定是null,设置一个空节点初始化为头,再次循环直到设置为tail节点。现在可以看acquireQueued方法了,这个方法返回false,代表没有被打断,否则是被打断了。
获取前驱,判断是不是节点,如果是头节点则获取锁。获取成功设置当前几点为头点,释放之前头节点。如果不是头节点或者获取锁失败,则会执行shouldParkAfterFailedAcquire()去设置前驱节点状态为-1。所以说到这里已经两次去获取锁了,head节点也可以理解为当前获取到锁的节点。
parkAndCheckInterrupt 调用LockSupport.park(this);休眠。等待别人唤醒
现在看解锁tryrelease ,锁状态减1。头节点不为null,且状态不为0,则去唤醒其他线程
设置当前节点状态为0,找到最近一个节点状态小于等于0的解锁
先介绍这么多,这篇主要介绍阻塞队列,后面再介绍条件队列
以上是关于ReentrantLock源码分析的主要内容,如果未能解决你的问题,请参考以下文章