分析下ReentrantLock调用lock的fairSync版本

reentrantLock调用lock的fairSync版本

1 reentrantLock调用lock

public void lock() {
    sync.lock();    -> 2 :调用sync的lock方法,选的fairsync作为例子
}

2 调用acquire方法,尝试获取锁

final void lock() {
        acquire(1);   -> 3
  }

3 (1)获取锁成功,退出. (2)获取锁失败,添加node至AQS尾部.详细请看方法指示的标号

	 public final void acquire(int arg) {
  	 if (!tryAcquire(arg) &&   -->4
      acquireQueued(addWaiter(Node.EXCLUSIVE), arg))      ---->6(5) 
      selfInterrupt();
	}

4 原子地获取锁,(1)如果锁未被占用,获取成功则将state由0添加至1.(2)如果锁被当前线程占用,重入则添加state计数器,(3)否则失败

     protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        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;
    }

5 将代表当前线程的Node原子性地添加至队列尾部.(1).尾部不为空则cas操作尾部引用设置为当前node.并且将之前的尾部node与当前node相连. (2)尾部为空则设置头尾为一个新的Node,然后设置当前node为尾

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

6 如果node的前节点为head,如果获取锁权限成功,则将头节点设置为当前节点,并且释放前节点,返回interrupted状态(设置interupted用)
如果前节点不为head或者获取锁权限失败, 则根据前驱节点的waitStatus如果为signal则阻塞当前线程,如果不为signal则设置为signal继续循环
循环

    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) &&       ---->7
                parkAndCheckInterrupt())									---->8
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node); -- 9
    }
}

7 前驱节点为signl则直接返回true…
如果前驱节点为cancel,则直到前驱结点的前驱…状态不为取消的节点,然后将此节点的后继者设置为当前节点. return false
否则cas原子性地将前节点地status设置为signal return false

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

8 locksupport 将当前线程的blocker设置为当前AQS .阻塞当前线程. 醒了就设置为空.传递interupted状态

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}
private static void setBlocker(Thread t, Object arg) {
    // Even though volatile, hotspot doesn't need a write barrier here.
    UNSAFE.putObject(t, parkBlockerOffset, arg);
}

9 将node的waitStatus置为CANCELLED,将与之相连的已被取消的前结点全部移出AQS,然后将前结点的状态置为SIGNAL,并且将当前结点的后一个结点连接在之后(非cancel的情况下).如果失败了,那么就执行10

private void cancelAcquire(Node node) {
    // Ignore if node doesn't exist
    if (node == null)
        return;

    node.thread = null;

    // Skip cancelled predecessors
    Node pred = node.prev;
    while (pred.waitStatus > 0)
        node.prev = pred = pred.prev;

    // predNext is the apparent node to unsplice. CASes below will
    // fail if not, in which case, we lost race vs another cancel
    // or signal, so no further action is necessary.
    Node predNext = pred.next;

    // Can use unconditional write instead of CAS here.
    // After this atomic step, other Nodes can skip past us.
    // Before, we are free of interference from other threads.
    node.waitStatus = Node.CANCELLED;

    // If we are the tail, remove ourselves.
    if (node == tail && compareAndSetTail(node, pred)) {
        compareAndSetNext(pred, predNext, null);
    } else {
        // If successor needs signal, try to set pred's next-link
        // so it will get one. Otherwise wake it up to propagate.
        int ws;
        if (pred != head &&
            ((ws = pred.waitStatus) == Node.SIGNAL ||
             (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
            pred.thread != null) {
            Node next = node.next;
            if (next != null && next.waitStatus <= 0)
                compareAndSetNext(pred, predNext, next);
        } else {
            unparkSuccessor(node); -->10
        }

        node.next = node; // help GC
    }
}  

10.对于node后一个结点,如果waitstatus 为cancel或者为空,则从AQS尾部开始,找到第一个不为空的结点赋值给s变量.
最后唤醒s结点代表的线程.

private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值