• 多线程高并发编程(3) -- ReentrantLock源码分析AQS


    背景:

      AbstractQueuedSynchronizer(AQS)

    public abstract class AbstractQueuedSynchronizer
        extends AbstractOwnableSynchronizer
        implements java.io.Serializable
    • 介绍

    1. 提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。 该类被设计为大多数类型的同步器的有用依据,这些同步器依赖于单个原子int值来表示状态。 子类必须定义改变此状态的受保护方法,以及根据该对象被获取或释放来定义该状态的含义。 给定这些,这个类中的其他方法执行所有排队和阻塞机制。 子类可以保持其他状态字段,但只以原子方式更新int使用方法操纵值getState()setState(int)compareAndSetState(int, int)被跟踪相对于同步
    2. 子类应定义为非公共内部助手类,用于实现其封闭类的同步属性。 AbstractQueuedSynchronizer类不实现任何同步接口。 相反,它定义了一些方法,如acquireInterruptibly(int) ,可以通过具体的锁和相关同步器来调用适当履行其公共方法。
    3. 此类支持默认独占模式共享模式。【使用模板模式来定义是独占还是共享模式】 当以独占模式获取时,尝试通过其他线程获取不能成功。 多线程获取的共享模式可能(但不需要)成功。 除了在机械意义上,这个类不理解这些差异,当共享模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。 在不同模式下等待的线程共享相同的FIFO队列。 通常,实现子类只支持这些模式之一,但是两者都可以在ReadWriteLock中发挥作用 。 仅支持独占或仅共享模式的子类不需要定义支持未使用模式的方法。
    4. 这个类定义的嵌套AbstractQueuedSynchronizer.ConditionObject可用于作为一类Condition由子类支持独占模式用于该方法的实施isHeldExclusively()份报告是否同步排他相对于保持在当前线程,方法release(int)与当前调用getState()值完全释放此目的,和acquire(int) ,给定此保存的状态值,最终将此对象恢复到其先前获取的状态。 AbstractQueuedSynchronizer方法将创建此类条件,因此如果不能满足此约束,请勿使用该约束。 AbstractQueuedSynchronizer.ConditionObject的行为当然取决于其同步器实现的语义。
    5. 该类为内部队列提供检查,检测和监控方法,以及条件对象的类似方法。 这些可以根据需要导出到类中,使用AbstractQueuedSynchronizer进行同步机制。
    6. 此类的序列化仅存储底层原子整数维持状态,因此反序列化对象具有空线程队列。 需要可序列化的典型子类将定义一个readObject方法,可以将其恢复为readObject时的已知初始状态。

    一.ReentrantLock的lock和unlock源码解析

    • 使用流程分析:A、B两个线程同时执行lock()方法获取锁,假设A先执行获取到锁,此时state值加1,如果线程A在继续执行的过程中又执行了lock()方法,线程A会直接获取锁,同时state值加1,state的值可以简单理解为线程A执行lock()方法的次数;当线程B执行lock()方法获取锁时,会将线程B封装成Node节点,并将其插入到同步等待队列的尾部,然后阻塞当前线程,等待被唤醒再次尝试获取锁;线程A每次执行unlock()方法都会将state值减1,直到state的值等于零则表示完全释放掉了线程A持有的锁,此时将从同步等待队列的头节点开始唤醒阻塞的线程,阻塞线程恢复执行,再次尝试获取锁。ReentrantLock公平锁的实现使用了AQS的同步等待队列和state。
    • lock流程:

    1. 调用同步器Sync的抽象方法lock,由公平锁FairSync实现
    2. 调用AQS的acquire获取锁
      1. 尝试获取锁:公平锁FairSync的tryAcquire
        1. 第一次获取锁,若队列没有前节点和设置状态成功,存储当前线程,返回true,表示获取成功;
        2. 如果是重入获取,锁持有数量+1;
      2. 获取锁失败,把当前线程加入等待队列中,并对等待队列进行阻塞,不断竞争获取锁:acquireQueued遍历等待队列addWaiter,若有头节点则从队列中取出来,若没有则进行中断;
    • unlock流程:

    1. 调用同步器的release方法,有AQS实现;
    2. tryRelease释放锁,由Sync实现
      1. 锁数量-1;
      2. 当前线程和保存的线程不一致抛出异常;
      3. 锁数量为0则进行释放锁,把独占线程设置为null,修改状态; 
      1 //===========================ReentrantLock源码===============================
      2 public class ReentrantLock implements Lock, java.io.Serializable {
      3     private final Sync sync;//同步器
      4     public void lock() {//获取锁
      5             sync.lock();//调用同步器Sync的lock,由FairSync实现
      6     }
      7     public void unlock() {//使用锁
      8         sync.release(1);//调用同步器的release,由AQS实现
      9     }
     10 
     11 
     12     //内部类,同步器继承AQS,实现tryRelease释放锁
     13     abstract static class Sync extends AbstractQueuedSynchronizer{
     14         abstract void lock();//获取锁抽象方法,由FairSync实现
     15 //===========================释放锁===============================
     16         protected final boolean tryRelease(int releases) {
     17             int c = getState() - releases;//锁数量-1
     18             //当前线程和保存的线程不一致
     19             if (Thread.currentThread() != getExclusiveOwnerThread())
     20                 throw new IllegalMonitorStateException();
     21             boolean free = false;
     22             if (c == 0) {//持有的锁数量为0
     23                 free = true;//释放锁
     24                 setExclusiveOwnerThread(null);//当前独占线程为null
     25             }
     26             setState(c);//设置状态
     27             return free;
     28         }
     29     }
     30 
     31     //内部类,公平锁继承同步器,实现lock方法
     32     static final class FairSync extends Sync {
     33             //===========================获取锁===============================
     34             final void lock() {
     35                 acquire(1);//调用AQS的acquire
     36             }
     37             protected final boolean tryAcquire(int acquires) {
     38                 final Thread current = Thread.currentThread();//获得当前线程
     39                 /**getState是AQS的Node的waitStatus,其值有
     40                 *CANCELLED =  1
     41                 *SIGNAL    = -1
     42                 *CONDITION = -2
     43                 *PROPAGATE = -3
     44                 */
     45                 int c = getState();
     46                 //c初始值为0,0表示不是以上的状态;hasQueuedPredecessors之前是否有节点,
     47                 //如果是true表示这个线程的前面还有节点应该让前面的节点先获取锁,当前线程获取失败;
     48                 //【非公平锁少了hasQueuedPredecessors这个判断】
     49                 //compareAndSetState CAS比较,设置当前状态为1;setExclusiveOwnerThread当前线程设置为独占线程
     50                 if (c == 0) {
     51                     if (!hasQueuedPredecessors() &&
     52                         compareAndSetState(0, acquires)) {
     53                         setExclusiveOwnerThread(current);
     54                         return true;//获取成功
     55                     }
     56                 }
     57                 else if (current == getExclusiveOwnerThread()) {//如果是当前线程,表示重入
     58                     int nextc = c + acquires;//锁数量+1
     59                     if (nextc < 0)//小于0表示溢出
     60                         throw new Error("Maximum lock count exceeded");
     61                     setState(nextc);//更新状态
     62                     return true;//获取成功
     63                 }
     64                 return false;//获取失败
     65             }
     66     }
     67 }
     68 
     69 
     70 
     71 //=============AbstractQueuedSynchronizer源码==============
     72 public abstract class AbstractQueuedSynchronizer
     73     extends AbstractOwnableSynchronizer
     74     implements java.io.Serializable{
     75 //===========================获取锁===============================
     76     //以独占模式获取,忽略中断。通过调用至少一次tryAcquire(int)实现,成功返回。否则线程排队,
     77     //可能会重复阻塞和解除阻塞,直到成功才调用tryAcquire(int)。
     78     public final void acquire(int arg) {//FairSync的lock调用
     79             //tryAcquire获取锁;acquireQueued线程加入到了等待队列中,进行阻塞等待,竞争获取锁;
     80             //addWaiter其他线程获取锁失败添加到等待队列中;Node.EXCLUSIVE节点独占,为null
     81             if (!tryAcquire(arg) &&
     82                 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
     83                 selfInterrupt();
     84     }
     85     protected boolean tryAcquire(int arg) {//acquire调用,由FairSync实现
     86         throw new UnsupportedOperationException();
     87     }
     88     final boolean acquireQueued(final Node node, int arg) {//acquire调用
     89         boolean failed = true;
     90         try {
     91             boolean interrupted = false;
     92             for (;;) {
     93                 final Node p = node.predecessor();//获取前一个节点
     94                 if (p == head && tryAcquire(arg)) {//如果获取的节点为头节点并且获取到锁
     95                     setHead(node);//当前节点设置为头节点
     96                     p.next = null;//头节点下一节点为空,即把当前节点从队列中移除出来
     97                     failed = false;
     98                     return interrupted;
     99                 }
    100               //当前节点不是头节点,parkAndCheckInterrupt让当前线程处于阻塞等待状态由其他线程唤醒
    101                 if (shouldParkAfterFailedAcquire(p, node) &&
    102                     parkAndCheckInterrupt())
    103                     interrupted = true;
    104             }
    105         } finally {
    106             if (failed)
    107                 cancelAcquire(node);
    108         }
    109     }
    110     private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {//acquireQueued调用
    111         int ws = pred.waitStatus;//获取前一节点的等待状态
    112         if (ws == Node.SIGNAL)//如果状态为唤醒状态
    113             return true;
    114         if (ws > 0) {//处于CANCELLED状态
    115             do {
    116                 node.prev = pred = pred.prev;//1.把所有处于CANCELLED状态的节点移除
    117             } while (pred.waitStatus > 0);
    118             pred.next = node;//2.把所有处于CANCELLED状态的节点移除
    119         } else {
    120             compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//设置为SIGNAL状态
    121         }
    122         return false;
    123     }
    124     private Node addWaiter(Node mode) {//acquireQueued的参数,在acquire中调用
    125         Node node = new Node(Thread.currentThread(), mode);//创建Node,当前线程指向node
    126         Node pred = tail;//前节点指向尾节点【双向链表】
    127         if (pred != null) {//尾节点不为空
    128             node.prev = pred;//当前线程节点指向尾节点
    129             if (compareAndSetTail(pred, node)) {//CAS比较,把当前线程节点更新为尾节点
    130                 pred.next = node;//前尾节点的下一节点指向当前尾节点
    131                 return node;
    132             }
    133         }
    134         enq(node);//如果尾节点为空,把当前节点放到一个初始化节点或添加到节点中做为尾节点
    135         return node;
    136     }
    137     private Node enq(final Node node) {//addWaiter调用
    138         for (;;) {
    139             Node t = tail;
    140             if (t == null) { // 尾节点为空
    141                 if (compareAndSetHead(new Node()))//创建新节点并维护一个头节点
    142                     tail = head;//把当前节点设置为头节点
    143             } else {
    144                 node.prev = t;//当前节点指向尾节点
    145                 if (compareAndSetTail(t, node)) {//把当前节点更新为尾节点
    146                     t.next = node;//前尾节点的下一节点指向当前尾节点
    147                     return t;
    148                 }
    149             }
    150         }
    151     }
    152     static void selfInterrupt() {//acquire调用
    153         Thread.currentThread().interrupt();//当前线程中断
    154     }
    155 //===========================释放锁===============================
    156     public final boolean release(int arg) {//ReentrantLock的unlock调用
    157         if (tryRelease(arg)) {//当前线程锁释放成功,唤醒其他线程进行资源的竞争
    158             Node h = head;
    159             if (h != null && h.waitStatus != 0)
    160                 unparkSuccessor(h);
    161             return true;
    162         }
    163         return false;
    164     }
    165     protected boolean tryRelease(int arg) {//release调用,由Sync实现
    166         throw new UnsupportedOperationException();
    167     }
    168 }

      备注:公平锁是针对锁的获取而言,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序;非公平锁会进行插队获取锁;

    二.AQS重写锁

    流程:

    1. 实现Lock,重写实现方法lock、lockInterruptibly、tryLock、unlock、newCondition;
    2. 内部类继承AQS,重写tryAcquire和tryRelease;
     1 public class MyAQSLock implements Lock{
     2     private MyAQS myAQS;
     3     private class MyAQS extends AbstractQueuedSynchronizer{
     4         @Override
     5         protected boolean tryAcquire(int arg) {
     6             int state = getState();//获取状态
     7             Thread thread = Thread.currentThread();
     8             if(state==0){//线程第一次进来获取,状态为0,表示可以拿到锁
     9                 if(compareAndSetState(0,arg)){//更新状态
    10                     setExclusiveOwnerThread(Thread.currentThread());//设置为独占线程,其他线程进来进入等待
    11                     return true;//获取成功
    12                 }
    13             }else if(getExclusiveOwnerThread()== thread){//重入,存储线程等于当前线程
    14                 setState(state+1);//锁数量+1
    15                 return true;
    16             }
    17             return false;//获取失败
    18         }
    19 
    20         @Override
    21         protected boolean tryRelease(int arg) {
    22             //当前线程不是存储线程
    23             if(Thread.currentThread() != getExclusiveOwnerThread()){
    24                 throw new RuntimeException();
    25             }
    26             int state = getState()-arg;//锁数量-1
    27             boolean flag = false;
    28             if(state==0){//锁数量为0
    29                 setExclusiveOwnerThread(null);//独占锁为null,表示可以让其他线程进来竞争获取资源了
    30                 flag=true;
    31             }
    32             setState(state);//更新状态
    33             return flag;
    34         }
    35 
    36         public ConditionObject newConditonObject(){
    37             return new ConditionObject();
    38         }
    39     }
    40     @Override
    41     public void lock() {
    42         myAQS.acquire(1);
    43     }
    44 
    45     @Override
    46     public void lockInterruptibly() throws InterruptedException {
    47         myAQS.acquireInterruptibly(1);
    48     }
    49 
    50     @Override
    51     public boolean tryLock() {
    52         return myAQS.tryAcquire(1);
    53     }
    54 
    55     @Override
    56     public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    57         return myAQS.tryAcquireNanos(1,unit.toNanos(time));
    58     }
    59 
    60     @Override
    61     public void unlock() {
    62             myAQS.release(1);
    63     }
    64 
    65     @Override
    66     public Condition newCondition() {
    67         return myAQS.newConditonObject();
    68     }
    69 }
  • 相关阅读:
    UML 类与类之间的关系
    HTTP协议基础
    LDAP介绍
    UML 类与类之间的关系
    我的桌面
    RoR的OO与敏捷[1][88250原创]
    Ubuntu7.10纯仿Leopard[00原创]
    37个我爱Ruby的理由
    在Ubuntu 7.10上安装Rails[00整理]
    RoR的OO与敏捷[1][88250原创]
  • 原文地址:https://www.cnblogs.com/huangrenhui/p/12712475.html
Copyright © 2020-2023  润新知