基于AQS公平锁源码导读

一.我们先来创建一个公平锁

public static void main(String[] args)  {
    
  Lock lock = new ReentrantLock(true);
  lock.lock();
  
}
复制代码

ReentrantLock默认为非公平锁,传参数为true时才创建出公平锁

下面看下lock方法的实现:

final void lock() {
    acquire(1);
}
复制代码
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
复制代码

tryAcquire:尝试获取锁 acquireQueued:将当前线程放入到,等待队列,并且不断的尝试获取锁。 selfInterrupt:中断该线程

二.tryAcquire只是尝试一次获取锁

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    //获取状态
    int c = getState();
    //状态为0,表示没有线程获得锁
    if (c == 0) {
        if (!hasQueuedPredecessors() &&
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //当前线程为独占线程,表示已经获取到锁
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        //获取占有的次数
        setState(nextc);
        return true;
    }
    return false;
}
复制代码

/**

  • The synchronization state.

*/

private volatile int state;

若state==0则表示当前锁没有被线程持有,进入下一步,因为是公平锁,所以线程在尝试获取锁时需要判断当前等待队列里面是否已经有线程在等待了,若是有的话,当前线程就不会去尝试获取锁,

若是当前锁已经被线程持有了,即state != 0,那么会比较当前线程和持有锁线程的关系,即判断当前是否是持有锁的线程又一次来尝试获取锁,这也是reentrantlock是可重入锁的原因,在current == getExclusiveOwnerThread()时,会将state+1,并且返回true,而对应的在释放锁的时候,肯定也是需要释放多次的。

public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    //尾节点
    Node t = tail; // Read fields in reverse initialization order
    //头节点
    Node h = head;
    Node s;
    //头节点不等于尾节点
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}
复制代码

这里先说一下hasQueuedPredecessors()方法的作用,主要是用来判断线程需不需要排队,因为队列是FIFO的,所以需要判断队列中有没有相关线程的节点已经在排队了。有则返回true表示线程需要排队,没有则返回false则表示线程无需排队。

等待队列的头节点并不是一个实际的线程节点,h != t&&(s = h.next) == null代表的情况是,头节点已经创建,第一个等待线程已经成为了尾节点,但是头节点的next还未指向尾节点,所以此时h.next==null。

protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
复制代码

设置当前拥有独占访问权限的线程

扫描二维码关注公众号,回复: 14545386 查看本文章
protected final void setExclusiveOwnerThread(Thread thread) {
    exclusiveOwnerThread = thread;
}
复制代码

//设置状态,这个状态表示线程占有的次数

protected final void setState(int newState) {
    state = newState;
}
复制代码

三.进入等待队列:

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;
        //当前节点设置为尾节点,失败之后,进入enq方法,进行循环
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}
复制代码
private Node enq(final Node node) {
    for (;;) {
        //指向尾节点
        Node t = tail;
        //尾节点为空
        if (t == null) { // Must initialize
            //头节点赋值
            if (compareAndSetHead(new Node()))
                //尾节点指向头节点
                tail = head;
        } else {
            //节点前驱指向尾节点
            node.prev = t;
            //当前节点设置为尾节点,此处失败的话,重新开始循环
            if (compareAndSetTail(t, node)) {
                //next指向新的尾节点
                t.next = node;
                return t;
            }
        }
    }
}
复制代码

四.循环尝试获取锁

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            //获取节点的前驱节点
            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);
    }
}
复制代码
private final boolean compareAndSetTail(Node expect, Node update) {
    return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
复制代码

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    //获取前驱节点的状态
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * 前驱节点已经设置了SIGNAL,闹钟已经设好,现在我可以安心睡觉(阻塞)了。
         * 如果前驱变成了head,并且head的代表线程exclusiveOwnerThread释放了锁,
         * 就会来根据这个SIGNAL来唤醒自己
         */
        return true;
    //前驱节点已取消
    if (ws > 0) {
        /*
         * 发现传入的前驱的状态大于0,即CANCELLED。说明前驱节点已经因为超时或响应了中断,
         * 而取消了自己。所以需要跨越掉这些CANCELLED节点,直到找到一个<=0的节点
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
          /*
           * 进入这个分支,ws只能是0或PROPAGATE。
           * CAS设置ws为SIGNAL
           */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}
复制代码
private final boolean parkAndCheckInterrupt() {
    //线程进入到waiting状态
    LockSupport.park(this);
    return Thread.interrupted();
}
复制代码

猜你喜欢

转载自juejin.im/post/7186264859586887736
今日推荐