JDK1.8 ReentrantLock相关源码

java.util.concurrent.locks.ReentrantLock内部维护了AbstractQueuedSynchronizer的实现类java.util.concurrent.locks.ReentrantLock.Sync,主要是基于AbstractQueuedSynchronizer实现的一些同步功能,

其中AbstractQueuedSynchronizer内部也是基于LockSupport.park(this);LockSupport.unpark(node.thread)的基本加锁解锁功能和大量的CAS 操作,实现数据的同步和线程的调度功能,为其他线程相关操作类提供了一个基础的工具类。

其中CAS操作系统调用代价低,原因如下(参考AI回答)

1. 硬件级原子指令支持

  • CAS 操作通过 CPU 提供的‌单条原子指令‌(如 x86 的 cmpxchg、ARM 的 ldrex/strex)直接实现比较与交换操作,‌无需进入内核态‌。
  • 该指令在单个时钟周期完成内存值与预期值的比对和更新,‌完全在用户态执行‌,避免了系统调用上下文切换的开销。

2. 无锁化设计减少阻塞

  • 无锁自旋‌:CAS 通过循环重试(自旋)处理竞争,线程始终处于运行状态,‌无线程挂起/唤醒操作‌,规避了内核调度成本。
  • 对比锁机制‌:传统锁(如 synchronized)在竞争失败时触发线程阻塞,涉及内核态切换(如 futex 系统调用)和上下文保存/恢复,开销显著高于自旋。

3. 内核交互的极简触发

  • CAS ‌仅在发生竞争时依赖用户态指令‌,不强制与内核交互。
  • 仅当多核 CPU 缓存不一致时,通过 ‌MESI 协议或总线锁定‌协调缓存(硬件层面完成),‌极少触发内核介入

4. 性能对比数据

场景CAS 机制synchronized差异来源
无竞争操作≈10ns(用户态CAS指令)≈20ns(偏向锁CAS)67
单一竞争≈100ns(自旋数次)>1000ns(锁膨胀+内核阻塞)47
高并发竞争自旋消耗CPU(需控制重试)阻塞队列调度稳定412

 java.util.concurrent.locks.ReentrantLock#lock

NonfairSync和FairSync继承Sync,分别实现了一些非公平和公平获取锁的逻辑,其中FairSync基于NonfairSync。

源码中206行可知,AQS中状态为0代表为线程占用,1代表有线程占用。所谓的锁,本质是一些数据标识。setExclusiveOwnerThread方法代表当前线程获取锁成功,设置为AQS中的独占线程。如获取锁失败,再进入209行尝试获取锁。

 进入java.util.concurrent.locks.ReentrantLock.NonfairSync#tryAcquire====>java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire

 从131-137行可以看出新来的线程可以直接根据当前状态判断是否能拿到锁,不需要和AQS队列里的线程竞争,这就是非公平的体现。138行-144行看出如果当前线程已经是AQS中的独占线程是,再加锁时,状态会叠加,体现了可重入的特性(这段代码中当前线程是独占执行的,不需要CAS操作)。

 如果nonfairTryAcquire获取失败,会先进入

java.util.concurrent.locks.AbstractQueuedSynchronizer#addWaiter

该方法主要是创建AQS双向链表中的节点,并加入链表的尾部,每个节点封装了线程对象。

进入java.util.concurrent.locks.AbstractQueuedSynchronizer#enq可以看出链表中初始以lazy的方式创建head节点

再进入java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireQueued

这个方法主要是循环获取锁,如获取不到则阻塞当前线程,此时当前线程已在AQS链表中,可有其他线程(链表中前一个节点)唤醒。从862-868行看出获取锁是从链表的头部节点开始的。头部代表活跃的线程。

进入java.util.concurrent.locks.AbstractQueuedSynchronizer#shouldParkAfterFailedAcquire。可以看出,前一节点waitStatus状态必须为Node.SIGNAL,当前节点才能阻塞。因为阻塞节点的唤醒必须基于前一节点waitStatus状态。808-811行类似以lazy方式根据状态更新双向链表

java.util.concurrent.locks.ReentrantLock#unlock

java.util.concurrent.locks.ReentrantLock#unlock底层调用了java.util.concurrent.locks.AbstractQueuedSynchronizer#release方法

 在java.util.concurrent.locks.ReentrantLock.Sync#tryRelease方法中,当前AQS的state字段减去参数arg,当state为0时,释放锁,唤醒其他线程。

进入java.util.concurrent.locks.AbstractQueuedSynchronizer#unparkSuccessor可看出先从头部开始取一个节点并unpark,取不到的话再从队尾开始取节点并unpark

java.util.concurrent.locks.Condition 

 使用示例

            Condition condition = lock.newCondition();
            condition.await();
            System.out.println("等待结束!");
            condition.signal();

Condition主要是用于线程的主动阻塞,类似Object.wait()。参考java.lang.Thread.State线程状态

    /**
     * A thread state.  A thread can be in one of the following states:
     * <ul>
     * <li>{@link #NEW}<br>
     *     A thread that has not yet started is in this state.
     *     </li>
     * <li>{@link #RUNNABLE}<br>
     *     A thread executing in the Java virtual machine is in this state.
     *     </li>
     * <li>{@link #BLOCKED}<br>
     *     A thread that is blocked waiting for a monitor lock
     *     is in this state.
     *     </li>
     * <li>{@link #WAITING}<br>
     *     A thread that is waiting indefinitely for another thread to
     *     perform a particular action is in this state.
     *     </li>
     * <li>{@link #TIMED_WAITING}<br>
     *     A thread that is waiting for another thread to perform an action
     *     for up to a specified waiting time is in this state.
     *     </li>
     * <li>{@link #TERMINATED}<br>
     *     A thread that has exited is in this state.
     *     </li>
     * </ul>
     *
     * <p>
     * A thread can be in only one state at a given point in time.
     * These states are virtual machine states which do not reflect
     * any operating system thread states.
     *
     * @since   1.5
     * @see #getState
     */
    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

java层面定义了线程状态NEW,RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED。

Condition.await()和ReentrantLock.lock()底层都调用了LockSupport.park,所以他们的状态应该都是WAITING。

 

 进入java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#await()

 在进入java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#addConditionWaiter中可以看出,每个ConditionObject维护了一个单项链表,其中每个Node封装了线程信息,将当前线程封装节点加入Condition中的等待队列(这里队列和链表同义)。

 java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#await()第2036行在阻塞前先释放锁,激活另一个在就绪队列中的节点(AQS中的双向链表)。

第2038中判断当前节点是否在AQS中的双向链表中,如在AQS中的双向链表,说明已被其他线程调用condition.signal()释放,否则阻塞当前线程,

第2040行进入到

java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#checkInterruptWhileWaiting再进入java.util.concurrent.locks.AbstractQueuedSynchronizer#transferAfterCancelledWait

 

 可以看出这段代码是为了处理线程中断Thread.interrupt()和线程被激活ConditionObject.signal()同时发生的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值