深入理解AQS底层源码(一)——lock.lock()

前期准备:

1、可重入锁(递归锁):外层使用锁后,在内层仍然可以使用锁。同一个线程可以获取多个同一把锁。

优点:避免死锁。特点:锁对象是同一个对象

2、LockSupport:LockSupport.park(); LockSupport.unPark(Thread t);

类比 synchronized wait notify  ;   lock.newCondition await signal

wait notify必须和synchronized搭配使用且先wait后notify;
await signal必须和lock.newCondition搭配使用且先await后signal。

LockSupport.park(); LockSupport.unPark(Thread t); 不分前后顺序。

言归正传:

AbstractQueuedSynchronizer(AQS):state+CLH双向队列 ;node ;head(头)、tail(尾)、prev(前)、next(后)

本次以ReentrantLock的非公平锁为例:

场景:3个线程抢占一个资源,使用lock.lock(); 和 lock.unLock();

第一步:线程1:lock.lock();调用ReentrantLock的lock()方法,底层调用sync.lock();  Sync是继承了AbstractQueuedSynchronizer的ReentrantLock的抽象静态内部类。

NonfairSync继承Sync调用lock方法,通过CAS将state从0 -> 1,锁住当前线程1,线程1开始执行其任务,假设执行20min。

深入理解AQS底层源码(一)——lock.lock()

第二步:线程2也想要执行线程1的操作,调用lock方法发现state是1,并不是期望的0,所以调用acquire(1)方法。如上图的else中的方法。

深入理解AQS底层源码(一)——lock.lock()

第三步:线程2调用tryAcquire(arg)方法中的nonfairTryAcquire(acquires)方法,返回false;

current = 线程2;c = 1;getExclusiveOwnerThread() = 线程1;

深入理解AQS底层源码(一)——lock.lock()

第四步:线程2调用tryAcquire(arg)方法中的addWaiter(Node.EXCLUSIVE);

线程2 放到 node中,tail(尾指针 == null),执行enq(node)方法。

深入理解AQS底层源码(一)——lock.lock()

node是线程2,tail(尾指针 == null)执行compareAndSetHead(new Node());创建一个空的node示例,可以理解为傀儡节点。

(即双向链表的第一个节点不是实际的线程节点而是new的空节点,为了占位),head和tail都指向空节点

for循环第二次,node成为真正的线程2,tail = t 空节点,走else 线程2的前指针指向空节点,tail(尾指针)指向线程2,空节点的后指针指向线程2。

线程2节点入队完毕。

深入理解AQS底层源码(一)——lock.lock()

第五步:执行enq(node)方法完毕后,线程2入队成功,返回线程2节点。

线程3执行addWaiter(Node.EXCLUSIVE)方法时,tail = pred != null。tail 是线程2的节点,然后compareAndSetTail(pred, node),tail的指针指向线程3。

线程2的next指向线程3,返回线程3节点,线程3节点入队。

深入理解AQS底层源码(一)——lock.lock()

第六步:执行acquireQueued(final Node node, int arg)方法,node是线程2节点,p = head = 空节点。

执行第2个条件tryAcquire(arg),arg = 1. 此时线程1还在占用锁中,所以返回false。

线程1unlock()后,p == head && tryAcquire(arg) == true,head节点设置为线程2节点,原先的head节点的尾节点设为null,被GC回收。

线程1还在锁中时,线程3执行到 acquireQueued(final Node node, int arg)方法时,node = 线程3的节点,arg = 1。

Node p = node.predecessor()  = 线程2节点,head还是空节点。第1个条件返回false,开始执行到shouldParkAfterFailedAcquire(p, node)方法。

一直自旋直至返回true。

finally执行的是取消获取锁的程序。

深入理解AQS底层源码(一)——lock.lock()

开始执行shouldParkAfterFailedAcquire(p, node)方法,p = head = 空节点,node是线程2节点。

空节点的waitStatus = ws  = 0; 走到else里面执行 compareAndSetWaitStatus(pred, ws, Node.SIGNAL)方法,把head节点的waitStatus设值为-1且返回false。

线程2节点的waitStatus = ws  = -1且返回true,因为waitStatus时volatile修饰的。

线程2节点执行shouldParkAfterFailedAcquire(p, node)方法,返回true;线程2执行parkAndCheckInterrupt(),线程2park().

线程3执行到shouldParkAfterFailedAcquire(p, node)方法,返回true;p = 线程2节点,node是线程3节点;线程3执行parkAndCheckInterrupt(),线程3park().

深入理解AQS底层源码(一)——lock.lock()

深入理解AQS底层源码(一)——lock.lock()

以上是加锁lock的执行过程。