java--ReentrantLock源码解析


java.util.concurrent包中的工具实现核心都是AQS,了解ReentrantLock的实现原理,需要先理解AQS
还没有看AQS的建议先去了解AQS

ReentrantLock构造

在这里插入图片描述
在创建ReentrantLock时会给我们提供2种选择公平的个非公平的实现,在上面都不传的情况下默认就是非公平NonfairSync

NonfairSync (不公平锁)

lock

在这里插入图片描述

第一个判断compareAndSetState(0, 1) 通过cas的方式获取尝试把0修改为1,如果修改成功那么就设置锁的持有者为当前线程,如果获取锁失败执行acquire方法
在这里插入图片描述
acquire方法里会再一次尝试获取到锁,如果还是失败,调用addWaiter
构建Node队列

  • 黄色三角标识该node的waitStatus状态,其中0代表默认的正常状态
  • 其中第一个node用来占位,不关联线程称为哨兵
    在这里插入图片描述
    接下来是进入acquireQueued方法
    在这里插入图片描述
  final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 获取当前节点的前驱节点
                final Node p = node.predecessor();
                /**
                如果获取到的节点是head头节点,因为head是一个空节点
                说明他排在第一个,tryAcquire又去尝试获取锁,如果获取到
                 锁
                **/
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                /**
                 如果还是获取锁失败则进入阻塞队列
                 调用parkAndCheckInterrupt方法进行等待
                 **/
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

如果获取到的节点是head头节点,因为head是一个空节点
说明他排在第一个,tryAcquire又去尝试获取锁,如果还是失败则会调用shouldParkAfterFailedAcquire
把前驱节点改为-1,节点状态为-1的意思是它有职责去唤醒它的下一个节点
在这里插入图片描述

parkAndCheckInterrupt方法阻塞线程进行等待
在这里插入图片描述
如果多个线程经历竞争则会变成这样
在这里插入图片描述

lockInterruptibly(可中断的锁)

在这里插入图片描述
在这里插入图片描述
进入acquireInterruptibly方法第一步判断线程是否被打断过,如果打断则抛出异常,如果沒有被打断则开始竞争锁,如果获取失败进入doAcquireInterruptibly方法

    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
            // 判断线程是否被打断
        if (Thread.interrupted())
        	// 如果被打断抛出异常
            throw new InterruptedException();
        if (!tryAcquire(arg)) // 尝试获取到锁
        	// 获取失败
            doAcquireInterruptibly(arg);
    }

在这里插入图片描述
发现和lock的acquireQueued区别不大
在这里插入图片描述
在这里插入图片描述

一个是lock的acquireQueued只是返回了一个是否打断过的标识,而doAcquireInterruptibly方法则是直接抛出异常来停止线程

可重入

查询尝试获取锁的方法tryAcquire
在这里插入图片描述
nonfairTryAcquire里面就实现了可重入的机制

       /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            // 获取AQS State状态
            int c = getState();
            // 如果是0说明是没有持有者的状态
            if (c == 0) {
            	// 通过CAS来改变State状态 从0改为1来尝试获取锁
                if (compareAndSetState(0, acquires)) {
                    //设置当前锁的持有者为当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 如果状态不是0 说明该锁有持有者 
            // 判断持有者是不是和当前来获取锁的线程是否是同一个线程
            else if (current == getExclusiveOwnerThread()) {
            	// 如果是同一个线程 进行状态的+1 重入记数
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                // 重新设置AQS同步器State的值
                setState(nextc);
                return true;
            }
            return false;
        }

unLock

在这里插入图片描述
调用release方法
在这里插入图片描述
进入tryRelease判断

         protected final boolean tryRelease(int releases) {
        	// 获取到状态-1
            int c = getState() - releases;
            // 解锁只能是锁的持有线程 其他线程报错
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            // 因为这里涉及到重入机制 可能减去1 过后依然不是0
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            // 重新设置AQS State值
            setState(c);
            return free;
        }
  public final boolean release(int arg) {
        if (tryRelease(arg)) {// 走出tryRelease判断
            Node h = head;
            // 检查头结点后面是否还有待唤醒的线程 (waitStatus = -1 标识后面有线程等待唤醒)
            if (h != null && h.waitStatus != 0)
            	// 进入unparkSuccessor 去唤醒后面等待的线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

走出 tryRelease方法后检查头结点后面是否还有待唤醒的线程 (waitStatus = -1 标识后面有线程等待唤醒),进入unparkSuccessor 去唤醒后面等待的线程
在这里插入图片描述

NonfairSync (公平锁)

公平锁和非公平锁的主要区别在于tryAcquire方法

        --------------------非公平锁---------------------
        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;
        }
         --------------------公平锁---------------------
           protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // 先用hasQueuedPredecessors方法检查是否队列里面还有排队的线程
                // 如果有等待的线程条件不成立不会去竞争锁
                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;
        }

		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;
        // h!= t 头不等于尾的时候说明有等待的线程
        return h != t &&
        	// 没有第二个node 因为第一个node是占位符
            ((s = h.next) == null 
            //或者第二个node不是当前线程
            || s.thread != Thread.currentThread());
    }

await

   public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }

先判断当前线程是否被打断过addConditionWaiter方法向等待的node链表申请一个node当前节点的状态为-2 表示等待的node线程,fullyRelease方法去释放当前线程获取所以的锁(包括多次重入的也要释放–并去唤醒后面等待执行的线程)
在这里插入图片描述
调用 LockSupport.park(this)阻塞自己

signal

在这里插入图片描述
判断当前线程是否是锁的持有者,然后去获取阻塞队列对一个node节点执行doSignal方法

         private void doSignal(Node first) {
            do {
            	// 如果没有下一个
                if ( (firstWaiter = first.nextWaiter) == null)
                //  就把最后一个设置为null
                    lastWaiter = null;
                 // 断开连接 
                first.nextWaiter = null;
                // 转移到等待获取到锁的队列
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
        }
    final boolean transferForSignal(Node node) {
        /*
         * If cannot change waitStatus, the node has been cancelled.
         */
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        /*
         * Splice onto queue and try to set waitStatus of predecessor to
         * indicate that thread is (probably) waiting. If cancelled or
         * attempt to set waitStatus fails, wake up to resync (in which
         * case the waitStatus can be transiently and harmlessly wrong).
         */
         // enq方法插入该节点到尾部,返回前驱节点
        Node p = enq(node);
        int ws = p.waitStatus;
        // CAS修改前驱节点的状态为-1 说明他有责任唤醒后面节点
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        	// 然后唤醒
            LockSupport.unpark(node.thread);
        return true;
    }

enq方法插入该节点到尾部,返回前驱节点,通过CAS修改前驱节点的状态为-1 说明他有责任唤醒后面节点, LockSupport.unpark唤醒待获取锁的队列里面的线程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值