ReentrantLock的JDK源码阅读笔记


 本文为读取jdk源码的笔记所作。关注非公平锁。

读取AQS源码建议先了解下CAS机制,以及双向链表的相关知识。
 
 入口:ReentrantLock.lock()方法
   public  void  lock ( )  {
         sync . lock ( ) ;
     }
 
 调用sync的抽象方法lock
 
static  abstract  class  Sync  extends  AbstractQueuedSynchronizer  {
         private  static  final  long  serialVersionUID  =  -5179523762034025860 L ;
         /**
           * Performs { @link  Lock#lock}. The main reason for subclassing
           * is to allow fast path for nonfair version.
           */
         abstract  void  lock ( ) ;
       
     }
 
 默认具体由Sync的子类NonfairSync实现lock方法
 
  final  static  class  NonfairSync  extends  Sync  {
         private  static  final  long  serialVersionUID  = 7316153563782823691 L ;
         /**
           * Performs lock.  Try immediate barge, backing up to normal
           * acquire on failure.
           */
         final  void  lock ( )  {
              if  ( compareAndSetState ( 0 ,  1 ))
                   setExclusiveOwnerThread ( Thread . currentThread ( )) ;
              else
                   acquire ( 1 ) ;
         }
     }
 
 首先通过CAS机制尝试获取锁,如果成功则设置当前线程拥有此锁。获取锁失败则会调用acquire(1)继续执行

 
final  static  class  NonfairSync  extends  Sync  {
      final  void  lock ( )  {
              if  ( compareAndSetState ( 0 ,  1 ))
                   setExclusiveOwnerThread ( Thread . currentThread ( )) ;
              else
                   acquire ( 1 ) ;
         }
}
  static  abstract  class  Sync  extends  AbstractQueuedSynchronizer  {
     
  }
 
  public  abstract  class  AbstractQueuedSynchronizer
     extends  AbstractOwnableSynchronizer
     implements  java . io . Serializable  {
     public  final  void  acquire ( int  arg )  {
         if  ( ! tryAcquire ( arg )  &&
              acquireQueued ( addWaiter ( Node . EXCLUSIVE ) ,  arg ))
              selfInterrupt ( ) ;
     }
}
 
 acquire(1)会调用NonfairSync的父类的父类(AQS)的acquire()方法执行。
首先看tryAcquire(arg) 的实现,该类由子类NonfairSync重写,再次尝试通过CAS方式获得锁。
 
  protected  final  boolean  tryAcquire ( int  acquires )  {
              return  nonfairTryAcquire ( acquires ) ;
}
 
 
         final  boolean  nonfairTryAcquire ( int  acquires )  {
              final  Thread  current  =  Thread . currentThread ( ) ;
              int  c  =  getState ( ) ;
              if  ( c  ==  0 )  {
                   if  ( compareAndSetState ( 0 ,  acquires ))  {
                        setExclusiveOwnerThread ( current ) ;
                        return  true ;
                   }
              }
              else  if  ( current  ==  getExclusiveOwnerThread ( ))  {
                   int  nextc  =  c  +  acquires ;
                   if  ( nextc  <  0 )  // overflow
                        throw  new  Error ( "Maximum lock count exceeded" ) ;
                   setState ( nextc ) ;
                   return  true ;
              }
              return  false ;
         }
 

 如果再次通过CAS获得锁失败,将会调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg))方法,这是AQS机制的核心。
先看addWaiter(Node.EXCLUSIVE), arg)方法
 
     private  Node  addWaiter( Node  mode) {
         Node  node  =  new  Node( Thread. currentThread(),  mode);
         // Try the fast path of enq; backup to full enq on failure
         Node  pred  =  tail;
         if ( pred  !=  null) {
              node. prev  =  pred;
              if ( compareAndSetTail( prednode)) {
                   pred. next  =  node;
                   return  node;
             }
        }
         enq( node);
         return  node;
    }
 
addWaiter(Node.EXCLUSIVE), arg)方法,新建了一个当前线程的排它锁类型的节点。由于刚开始tail为null,因此直接调用enq(node)

Node的存储结构:
 
static  final  class  Node  {
         /** waitStatus value to indicate thread has cancelled */
         static  final  int  CANCELLED  =   1 ;
         /** waitStatus value to indicate successor's thread needs unparking */
         static  final  int  SIGNAL     =  -1 ;
         /** waitStatus value to indicate thread is waiting on condition */
         static  final  int  CONDITION  =  -2 ;
         /** Marker to indicate a node is waiting in shared mode */
         static  final  Node  SHARED  =  new  Node ( ) ;
         /** Marker to indicate a node is waiting in exclusive mode */
         static  final  Node  EXCLUSIVE  =  null ;
       
         volatile  Node  prev ;
       
         volatile  Node  next ;
        
         volatile  Thread  thread ;
        
         Node  nextWaiter ;
     }
 

 
 private Node enq ( final  Node  node ) {
         for  (;; ) {
              Node t = tail;
              if  ( t ==  null ) { // Must initialize
                   Node h = new Node (); // Dummy header
                   h .next = node;
                   node .prev = h;
                   if  ( compareAndSetHead( h )) {
                        tail = node;
                        return h;
                  }
             }
              else {
                   node .prev = t;
                   if  ( compareAndSetTail( tnode )) {
                        t .next = node;
                        return t;
                  }
             }
        }
    }
 
这段代码显然是建立双向链表典型代码。通过自旋和CAS成功的解决了,多线程下头节点的设置。头结点设置成功后,其余线程只能走到else代码段通过CAS设置后继节点。
该段代码的主要将没有获得锁的线程通过双向链表的形式进行存储。

 将新建的当前线程的排它锁类型的节点传入方法acquireQueued中
  final  boolean  acquireQueued ( final  Node  node ,  int  arg )  {
         try  {
              boolean  interrupted  =  false ;
              for  ( ;; )  {
                   final  Node  p  =  node . predecessor ( ) ;
                   if  ( p  ==  head  &&  tryAcquire ( arg ))  {
                        setHead ( node ) ;
                        p . next  =  null ;  // help GC
                        return  interrupted ;
                   }
                   if  ( shouldParkAfterFailedAcquire ( p ,  node )  &&
                        parkAndCheckInterrupt ( ))
                        interrupted  =  true ;
              }
         }  catch  ( RuntimeException  ex )  {
              cancelAcquire ( node ) ;
              throw  ex ;
         }
     }
 
该段代码主要含义是:如果该节点前继节点是头节点,再给你一次获取锁的机会,获取成功,该节点将成为头结点。其他节点通过
parkAndCheckInterrupt进行睡眠。

shouldParkAfterFailedAcquire方法是过滤那些CANCELLED的节点,关键要看懂do while 那段代码。可以自己画图理解。
 
  private  static  boolean  shouldParkAfterFailedAcquire ( Node  pred ,  Node  node )  {
         int  s  =  pred . waitStatus ;
         if  ( s  <  0 )
              /*
                * This node has already set status asking a release
                * to signal it, so it can safely park
                */
              return  true ;
         if  ( s  >  0 )  {
              /*
                * Predecessor was cancelled. Skip over predecessors and
                * indicate retry.
                */
         do  {
         node . prev  =  pred  =  pred . prev ;
         }  while  ( pred . waitStatus  >  0 ) ;
         pred . next  =  node ;
     }
         else
              /*
                * Indicate that we need a signal, but don't park yet. Caller
                * will need to retry to make sure it cannot acquire before
                * parking.
                */
              compareAndSetWaitStatus ( pred ,  0 ,  Node . SIGNAL ) ;
         return  false ;
     }
 
最后Thread.currentThread().interrupt();到这里锁就结束了。


AQS可以理解成一个存储争用锁的等待线程的存储以及状态变更的队列。
ReentrantLock.lock()通过CAS机制竞争到锁的线程继续执行,其余线程睡觉的机制实现同步机制。


释放锁关键为unparkSuccessor这段代码
 
     private  void  unparkSuccessor ( Node  node )  {
         /*
           * Try to clear status in anticipation of signalling.  It is
           * OK if this fails or if status is changed by waiting thread.
           */
         compareAndSetWaitStatus ( node ,  Node . SIGNAL ,  0 ) ;
         /*
           * Thread to unpark is held in successor, which is normally
           * just the next node.  But if cancelled or apparently null,
           * traverse backwards from tail to find the actual
           * non-cancelled successor.
           */
         Node  s  =  node . next ;
         if  ( s  ==  null  ||  s . waitStatus  >  0 )  {
              s  =  null ;
              for  ( Node  t  =  tail ;  t  !=  null  &&  t  !=  node ;  t  =  t . prev )
                   if  ( t . waitStatus  <=  0 )
                        s  =  t ;
         }
         if  ( s  !=  null )
              LockSupport . unpark ( s . thread ) ;
     }
 
LockSupport.unpark(s.thread);为唤醒等待线程,该线程唤醒之后会继续执行acquireQueued的for循环继续争用锁。








以上纯属个人解读
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值