首先简单介绍下AbstractQueuedSynchronizer是并发编程的同步器工具框架
特点:
1:阻塞式和相关同步器工具框架
2:AQS用一个state变量表示锁状态,子类去维护这个状态
3:独占锁只允许一个线程访问资源
4:共享模式可以允许多个线程共享资源
5:内部维护了一个等待队列,
6:条件变量来实现等待,唤醒机制,支持多个变量
我们如果需要实现自己的锁,可以去继承这个类,去实现自定义锁的逻辑
下面我们以ReentrantLock为例简单介绍一下加锁逻辑:
它持有了一个Sync静态类属性,继承了AbstractQueuedSynchronizer
AbstractQueuedSynchronizer主要属性介绍:
等待队列的头结点 private transient volatile Node head; 等待队列的尾部结点 private transient volatile Node tail;
同步器状态,默认为0表示未获取锁,1表示获取锁,支持重入,同一个线程加锁,state会+1,释放锁-1 private volatile int state;
再其父类还有一个属性,exclusiveOwnerThread 表示同步器持有锁的线程
我们通过构造器创建实例,可以指定布尔值,表示这个锁是否公平锁,还是非公平锁,默认是非公平锁
调用lock方法,默认会调用到非公平锁内部类的lock方法
场景1: 此时T1线程进行加锁,通过CAS设置同步器的状态status =1 ,设置成功表示加锁成功,并将持有锁的线程更新为当前线程,加锁过程完毕.
场景2: T1线程未释放锁,T2线程进行加锁
T2线程通过CAS更改state状态值,肯定会失败,此时进入acquire方法
调用tryAcquire()方法尝试进行加锁
获取当前线程T2,通过getState获取同步器状态,此时T1未释放锁,c==0不成立
并且当前持有锁的线程是T1,else if代码块逻辑也不会执行,返回false
tryAcquire方法的返回false,代码取反,所以会走addWait方法
private Node addWaiter(Node mode) { //构造Node节点 thread=t2,pre=null ,next=null waitstatus=0 Node node = new Node(Thread.currentThread(), mode); //将同步器的tail指针复制给pre ,此时tail指针是null Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //进入enq方法 enq(node); return node; }
//入队操作 private Node enq(final Node node) { for (;;) { //同步器尾部节点赋值给t=null Node t = tail; if (t == null) { // Must initialize //新创建一个节点Node(thread=null pre=null next=null waitStatus=0) //使用CAS设置Node节点为头部节点 if (compareAndSetHead(new Node())) //设置尾部节点也为Node tail = head; } else { //第二次循环,将线程T2的pre指针指向新创建Node节点 node.prev = t; //设置尾部节点为T2线程 if (compareAndSetTail(t, node)) { //设置Node节点next指针Node(thread=null pre=null next=指向T2 waitStatus=0) t.next = node; return t; } } } }
第一次循环
第二次循环示意图,结束循环后将T2的Node节点返回
调用acquireQueued
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //T2线程的前一个节点,并再次尝试加锁,此时加锁任然失败 final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } //获取锁失败之后,将 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
//第一次循环返回false,并更新waitStatus=-1,第二次循环进入返回true,并将T2线程park阻塞 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { //ws==0 int ws = pred.waitStatus; if (ws == Node.SIGNAL) return true; if (ws > 0) { do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { //将Node节点waitStatus设置为-1,表示需要唤醒后面的节点 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
waitStatus 表示队列中的节点是否需要唤醒别人
0 表示没有任何意义
-1 表示在队列中等待,需要唤醒后继节点
-2 表示条件队列状态 conditionObject
释放锁代码很简单就不再这里赘述了