ReentrantLock源码分析

Sync是ReentrantLock的一个内部抽象类,它继承了AQS,而ReentrantLock另外两个内部类:FairSync和NonFairSync则同时继承了Sync,并实现了Sync的lock方法,类图如下

 由类图可知要想理解ReentrantLock就需要理解AbstractQueuedSynchronizer(AQS)它实现了一个FIFO的队列,底层数据的数据结构是一个双向链表。

 AQS中的重要属性

private transient volatile Node head;//头结点

/**
 * Tail of the wait queue, lazily initialized.  Modified only via
 * method enq to add new wait node.
 */
private transient volatile Node tail; //尾节点

/**
 * The synchronization state.
 */
private volatile int state; //资源

/**
 * The current owner of exclusive mode synchronization.
 */
private transient Thread exclusiveOwnerThread;  //记录当前持有排它锁的线程

当第一个线程进行抢锁时没有竞争修改state标识成功代码获取锁并将exclusiveOwnerThread属性改为当前线程。

final void lock() {
	if (compareAndSetState(0, 1)) //当第一个线程抢锁时 修改资源state字段  成功改为1表示获得锁
		setExclusiveOwnerThread(Thread.currentThread());  //将持有锁的线程exclusiveOwnerThread字段修改为当前成功获取锁的线程
	else
		acquire(1);  //当有已经有线程获取锁时 其他线程进入抢锁进入此方法
}
 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&  //再次尝试拿锁/判断当前线程是否重入
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //addWaiter(Node.EXCLUSIVE), arg)  Node.EXCLUSIVE表示独占锁
            selfInterrupt();
    }
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;  //当等待线程首次执行时  tail为空
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node); //组件等待线程的链表结构
        return node;
    }
private Node enq(final Node node) {  //node当前线程节点
        for (;;) {
            Node t = tail; //第一次为空
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node())) //将head设置为一个哨兵节点
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) { //将尾指针指向当前线程节点
                    t.next = node;
                    return t;
                }
            }
        }
    }

经过循环会得到如下链表结构

 回到上面的acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 的 acquireQueued方法

 final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor(); //获取当前线程节点的上一个节点(从上图可知就是head节点也即哨兵节点)
                if (p == head && tryAcquire(arg)) {  //再次尝试获取锁
                    setHead(node);                   //获取锁成功 将当前线程节点改为head节点并将当前线程的thread置为空
                    p.next = null; // help GC 将原来head节点的next置为空
                    failed = false;
                    return interrupted;
                }

                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt()) //将当前线程挂起
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 进入shouldParkAfterFailedAcquire(p, node)方法中。

    /**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev.
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    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;
    }

waitStatus的默认值为0,所以这里的判断肯定是进入到else中,使用cas将waitStatus的值改变成Node.SIGNAL也就是-1。

 for循环 shouldParkAfterFailedAcquire(p, node)方法后已经将waitStatus的值改编成-1了,所以最终会返回true,也就是执行 parkAndCheckInterrupt() 方法 将当前线程挂起。

调用unlock
unlock会调用release(int arg) 方法

 public final boolean release(int arg) {
        if (tryRelease(arg)) {  //设置当前排它锁的线程为null,并将state设置为0 并返回true (如果重入则只会将state减一)
            Node h = head;
            if (h != null && h.waitStatus != 0)  //挂起时已经将非tail指向的所有节点的waitStatus 置为-1 即此判断返回true
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

调用unparkSuccessor(h)方法

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

Node s获取到node.next 也就是获取头结点后一个线程节点。因为waitStatus的默认值是0并且如果后面还有节点waitStatus的值也是-1所以当前if判断为false不会执行,继续执行到LockSupport.unpark(s.thread)唤醒线程,unlock方法执行结束。回到线程挂起

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

处线程继续执行,因为park过程中是可以被interrupt的,但是我们并没有去打断,所以我们返回是一个false。又回到死循环尝试获取到锁的方法中,因为是非公平锁中,当线程unlock释放锁后,通过tryAcquire()方法cas的方式来竞争获取锁。

 获取成功将当前节点设置为头节点。

总结:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值