AQS-ReentrantLock(加锁)源码浅析

1、ReentrantLock

         ReentrantLock实现主要依赖extends  AbstractQueuedSynchronizer,在源码里面xxxSync extends Sync实现lock 方法,而Sync 父类即是AbstractQueuedSynchronizer。

         实现方法如下:通过acquire(1);方法内部实现 AQS。

         final void lock() {

         acquire(1);

          }

2、acquire 方法 

(1)tryAcquire(arg),尝试获取资源,是否获取成功获取成功,直接放行继续执行。否则执行acquireQueued。

public final void acquire(int arg) {

if (!tryAcquire(arg) &&        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))       

 selfInterrupt();

}

3、acquireQueued方法

(1)将尝试获取资源失败的 线程,创建链表节点进入阻塞队列。

(2)addWaiter,添加并创建节点,Node.EXCLUSIVE 默认独占模式,NODE.SHARED 共享模式。

private Node addWaiter(Node mode) {

  Node node = new Node(Thread.currentThread(), mode);    

//获取链表尾部节点

 Node pred = tail;   

//尾部节点不为空,将当前节点指向 尾部节点,作为新的尾部节点

 if (pred != null) {       

 node.prev = pred;       

 if (compareAndSetTail(pred, node)) {          

  pred.next = node;           

 return node;

}}

//如果尾部节点 是  null,enq进行初始化节点,并cas 将当前创建新节点设置到链表尾部节点。

  enq(node);   

//返回当前节点

 return node;

}

(3)回到acquireQueued方法

final boolean acquireQueued(final Node node, int arg) {

//尝试是否失败

  boolean failed = true;    

try {     

//是否被打断

 boolean interrupted = false;

//注意这里将不断循环重试如下操作       

 for (;;) {          

//获取当前节点的前节点

final Node p = node.predecessor();

//如果当前节点的 前节点==head节点,那么当前节点即可尝试去获取资源,如果获取资源成功,表示当前节点的前节点已经无效,将当前节点设置为 head节点,将前节点置为null帮助GC回收。返回尝试获取状态,以及是否被打断。

if (p == head && tryAcquire(arg)) {                

setHead(node);               

 p.next = null; // help GC                

failed = false;               

 return interrupted;

}

//如果当前节点不是 head节点 or 尝试获取资源失败。

 if (shouldParkAfterFailedAcquire(p, node) &&                parkAndCheckInterrupt())   

             interrupted = true;

}} finally {     

//如果响应中断,异常表示当前节点,被取消

   if (failed)         

   cancelAcquire(node);

}}

(4)shouldParkAfterFailedAcquire,循环检测是否能够进行unpark阻塞状态,等待许可。

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {

//获取前节点的 节点状态,(SIGNAL:指示后续线程,需要许可解锁阻塞)

   int ws = pred.waitStatus;    

if (ws == Node.SIGNAL)

//前节点 状态 ==SIGNAL 返回true 由parkAndCheckInterrupt方法进行 park阻塞,暂停循环。

 return true;

if (ws > 0) {     

//前节点状态>0 (CANCELLED:表示线程已取消的waitStatus值),可能由于打断 or  timeout结束了当前节点。

  do {

//出现如上情况,当前节点会,不断循环往上查找到状态不是>0的节点,并把自己的前驱指向该节点。

node.prev = pred = pred.prev;

} while (pred.waitStatus > 0);       

 pred.next = node;

} else {      

//如果前节点状态 !>0 and != Node.SIGNAL,表示当前节点处于其他两种状态(CONDITION、PROPAGATE),将通过cas将前节点状态设置为 Node.SIGNAL。

 compareAndSetWaitStatus(pred, ws, Node.SIGNAL);

}    

return false;}

5、当从shouldParkAfterFailedAcquire方法获取park许可,接下来通过parkAndCheckInterrupt调用park进行阻塞,并返回当前线程是否被打断。

private final boolean parkAndCheckInterrupt() {

//阻塞等待 unpark许可,终止 for循环。

   LockSupport.park(this);  

 return Thread.interrupted();

}

6、cancelAcquire 取消当前节点在链表。

private void cancelAcquire(Node node) {  

 if (node == null)       

 return;    

node.thread = null;   

Node pred = node.prev;    

while (pred.waitStatus > 0)       

 node.prev = pred = pred.prev;   

Node predNext = pred.next;   

 node.waitStatus = Node.CANCELLED;    

 if (node == tail && compareAndSetTail(node, pred)) {        

compareAndSetNext(pred, predNext, null);

} else {         

 int ws;       

 if (pred != head &&((ws = pred.waitStatus) == Node.SIGNAL ||(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&            pred.thread != null) {      

      Node next = node.next;         

   if (next != null && next.waitStatus <= 0)           

     compareAndSetNext(pred, predNext, next);

} else {          

  unparkSuccessor(node);

}        

node.next = node; // help GC    }}

你可能感兴趣的:(AQS-ReentrantLock(加锁)源码浅析)