ReentranLock底层原理--AQS图解
2022-06-07 13:10:36   0  举报             
     
         
 剖析AQS底层原理,熟悉ReentranLock加锁解锁逻辑。
    作者其他创作
 大纲/内容
 是队列中有等待线程
    否
  setExclusiveOwnerThread()
  release(1)
  分支流转
  未获取到锁
  NonfairSync(非公平锁)
  阻塞当前线程,返回当前线程中断状态parkAndCheckInterrupt()
  LockSupport.unpark(s.thread)解除s.thread线程的阻塞
  调用解锁
  设置新的statesetState(c)
  子类
  总结:入CLH队列后尝试获取锁,先判断是否为第一个节点。是的话尝试获取锁,未获取到锁或不是第一个节点且非阻塞会进行自旋,重复尝试获取锁,如果阻塞,返回当前中断状态。
  内部类
  判断CLH队列中是否存在等待的线程!hasQueuedPredecessors()
  添加失败自旋保证队列全部入队
  调用加锁
  free = false
  1.先尝试获取锁
  是否获取到锁
  逻辑
  新的statec == 0 ?
  设置当前线程独占锁setExclusiveOwnerThread(Thread.currentThread())
  设置当前拥有独占访问权的线程
  acquire(1)
  selfInterrupt()->Thread.currentThread().interrupt()设置打断标记,将中断信号外传
  添加成功
  将当前线程对应的Node对象从CLH队列移除,并重新设置队列
  return free
  总结:线程加锁失败后,将当前线程添加到CLH队列,如果队列中有等待线程,将当前队列添加到队列尾部,如果没有,先检查是否初始化,初始化了就添加到队列尾部,未初始化就先初始化一个队列再添加注意:CLH队列会维护一个前驱节点,当前节点的pred == null 才是头节点,目的是方便判断,进行状态转换时也会简单许多
  模板方法模式
  AbstractQueuedSynchronizer
  获取当前拥有独占访问权的线程
  实现类
  AbstractOwnableSynchronizer
  当前节点是否为队列中的第一个节点?node.predecessor() == head ?
  类/接口
  判断是否是当前线程占用current == getExclusiveOwnerThread()
  设置当前占用访问权线程为nullsetExclusiveOwnerThread(null)
  getState()
  ReentrantLock(可重入锁)
  是否应该阻塞线程?shouldParkAfterFailedAcquirespan style=\"font-size: inherit;\
  state != 0被线程占用此时公平锁与非公平锁实现逻辑一致
  否自旋重复执行for循环尝试获取锁
  addWaiter(Node.EXCLUSIVE)
  总结:如果锁没有被占用:1.非公平锁直接尝试获取锁,2.公平锁先判断是否有等待线程,没有再尝试获取锁。3.如果被线程占用,则判断是否是当前线程占用。如果是就修改state状态,如果不是直接返回false执行后续代码。
  计算新的statec = getState() - releases如果不是当前线程占用锁抛异常
  初始化CLH队列compareAndSetHead(new Node())tail = head
  2.添加当前线程到CLH队列中EXCLSIVE独占模式
  tryRelease(arg) ?
  超类
  获取锁成功
  返回当前线程对应的Node对象
  自我中断设置打断标记
  是
  state == 0没有被线程占用
  Node pred = tail同步队列中是否有等待线程 pred != null ?
  非公平锁(不判断直接尝试获取锁)
  获取锁失败
  getExclusiveOwnerThread()
  Node h = head判断(头节点不为空,且waitStaaatus不为0)h != null && waitStatus != 0 
  1.粉色容器:类/方法关系图解2.红色容器:加锁逻辑图解3.灰色容器:解锁逻辑图解
  图例
   Node s = node.next;if (s == null || s.waitStatus > 0)(异常中断,废弃)赋值s = null,循环从尾部节点开始遍历,找到最前面的waitStatus<=0的线程,赋值s = t;
  成功
  返回true
  应该阻塞
  失败
  FairSync(公平锁)
  返回当前线程是否中断
  unparkSuccessor(h)唤醒节点的后继节点(如果存在)
  false
  free = true
  尝试获取锁成功返回TRUE
  返回false
  添加当前线程到队列中enq(Node)
  Sync
  lock()
  !tryAcquire(arg)
  是否获取成功
  尝试获取锁失败返回FALSE继续执行后续代码
  true当前线程不再占用锁
  (类中)方法
  公平锁
  修改Sync对象State的值nextc = c + acquiressetState(nextc)
  总结:1.调用unLock()时,首先判断当前线程是否为独占拥有线程 if (Thread.currentThread() != getExclusiveOwnerThread()) 不是则抛出异常。2.判断状态state值是否等于缓存状态值。即二者差是否为0。为0则设置当前占用访问权线程为null,改state为0,返回true。3.判断CLH队列头节点是否为空且waitStatus不为0,然后唤醒后续节点。将头节点后的waitStatus不大于零的pred指向head,然后释放锁。
  将当前队列添加到CLH队列尾
  方法中的逻辑
  true
  Lock
  队列是否初始化tail == null ?
  3.在CLH队队列中尝试获取锁
  获取到锁
  unLock()
  公平锁与否?
  尝试获取锁tryAcquire()
  添加成功与否
  Sync锁是否被线程占用?(state = 0?)
  不应该阻塞自旋重复执行for循环尝试获取锁
   
 
 
 
 
  0 条评论
 下一页
  
   
   
   
   
  
  
  
  
  
  
  
  
 