分析NonfairSync加锁/解锁过程

Posted 小N~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分析NonfairSync加锁/解锁过程相关的知识,希望对你有一定的参考价值。

类继承关系:

NonfairSync => Sync => AbstractQueuedSynchronizer

 

类NonfairSync

final void lock() {

    if (compareAndSetState(0, 1))

        setExclusiveOwnerThread(Thread.currentThread());

    else

        acquire(1);

}

分析:

compareAndSetState(0, 1):通过cas操作更新state状态,若成功,则获取到锁,否则,进行排队申请操作acquire

类AbstractQueuedSynchronizer

public final void acquire(int arg) {

    if (!tryAcquire(arg) &&

        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

        selfInterrupt();

}

分析:

tryAcquire方法最终实现为:

类Sync

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操作更新state状态,若成功,则获取到锁,否则,首先进行排队,

类AbstractQueuedSynchronizer

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(pred, node)) {

            pred.next = node;

            return node;

        }

    }

    enq(node);

    return node;

}

注意:

每一个线程被封装成一个Node节点。

进入enq方法——入队列

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)) {

                t.next = node;

                return t;

            }

        }

    }

}

分析:

这里针对head和tail属性的赋值均为cas原子操作。

最终模型如图:

 

如果多线程并发入队,最终结果如图:

 

注:prev和next分别为Node类的两个属性

入队操作结束后,开始请求队列acquireQueued

类AbstractQueuedSynchronizer

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);

    }

}

分析:

  1. Node p = node.predecessor()获取node的prev节点
  2. 如果prev==head节点并且tryAcquire返回true,则更新head节点为当前节点,并退出循环,也就获取到了锁。
  3. 否则的话,执行shouldParkAfterFailedAcquire和parkAndCheckInterrupt。
  4. setHead方法来修改head属性,改变队列的头部节点

  其中,shouldParkAfterFailedAcquire方法是针对waitStatus属性的修改

  private final boolean parkAndCheckInterrupt() {

      LockSupport.park(this);

      return Thread.interrupted();

  }

  LockSupport.park(this),使当前线程进入阻塞。

 

unlock分析

类AbstractQueuedSynchronizer

public final boolean release(int arg) {

    if (tryRelease(arg)) {

        Node h = head;

        if (h != null && h.waitStatus != 0)

            unparkSuccessor(h);

        return true;

    }

    return false;

}

类Sync

protected final boolean tryRelease(int releases) {

    int c = getState() - releases;

    if (Thread.currentThread() != getExclusiveOwnerThread())

        throw new IllegalMonitorStateException();

    boolean free = false;

    if (c == 0) {

        free = true;

        setExclusiveOwnerThread(null);

    }

    setState(c);

    return free;

}

分析:

主要工作就是设置还原state状态

类AbstractQueuedSynchronizer

private void unparkSuccessor(Node node) {

    int ws = node.waitStatus;

    if (ws < 0)

        compareAndSetWaitStatus(node, ws, 0);

    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);

}

分析:

  1. 入参node即head节点
  2. Node s = node.next;即获取到下一个节点,即正在阻塞中的线程
  3. LockSupport.unpark(s.thread);即激活线程

以上是关于分析NonfairSync加锁/解锁过程的主要内容,如果未能解决你的问题,请参考以下文章

ReentrantLock加锁及解锁过程之源码分析

从ReentrantLock加锁解锁角度分析AQS

并发系列五:基于两种案例来认识ReentrantLock源码解锁过程(公平锁)

追踪SQL Server执行delete操作时候锁的申请与释放过程

ORACLE用户的加锁解锁

二探ReentrantLock非公平锁的加解锁过程