详解JUC之锁——Lock与AQS(02)

本文深入探讨了Java并发工具包(JUC)中的锁机制,包括Lock接口与AbstractQueuedSynchronizer(AQS)类的基本概念及作用。文章详细介绍了Lock接口提供的主要方法,并解释了AQS作为多种锁实现的基础框架的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

详解JUC之锁——概述(01)中我对JUC中的锁进行了概述,下面我就介绍一下它们的根基Lock接口和AQS

Lock

看名字就知道Lock接口就是JUC中锁的顶级接口,支持语义不同的锁规则,比如说公平锁和非公平锁,独占锁(也可以叫互斥锁)和共享锁等。

它最主要的两个方法就是lock()unlock(),一看就知道是获取锁和释放锁。

还有一个比较有趣的方法是boolean tryLock(long time, TimeUnit unit)方法,这个方法没有lock()方法那么死心眼,它在尝试获取锁,获取到了就返回true,一段时间获取不到就算了,返回一个false

当然了,还有Condition newCondition()方法,返回与之关联的Condition对象

AbstractQueuedSynchronizer

AbstractQueuedSynchronizer就是大名鼎鼎的AQS类,怎么说呢,这个类就是JUC锁的根基,是JUC中不同锁的共同抽象类,锁的许多公共方法都是在这个类中实现的,我给你看看它类继承结构你就知道了

有没有发现,无论是带有Lock后缀的类如ReentrantLock还是不带Lock后缀的类如Semaphore它们里面的内部类Sync都继承了AQS。其实JUC中的各种锁只是一个表面装饰,它们里面真正实现功能的还是Sync

我再来给你看一个比根基更根基的东西,那就是AQS类的一个成员变量state

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

看注释说这个就是同步状态,可能到现在你还没有概念。那我问你,锁最主要的操作是什么?不就是获取锁释放锁嘛!!上面我讲了JUC中不同锁的很多公共方法是在AQS类实现的,其中就有获取锁和释放锁的方法,而我可以大声地告诉你,JUC中所有锁的获取锁和释放锁操作都是围绕着这个同步状态state进行加减操作。每次一个线程获取到锁即对应着这个state加1,释放锁就对应着这个state减1(Semaphore就特殊点,它能加n和减n),state为0的时候代表锁空闲。

公平锁和非公平锁

从上面我给出的AQS的继承结构图你会发现,很多锁的名叫Sync的内部类继承了AQS类,而这个Sync又分别有FairSyncNonfairSync类继承它,看名字就知道它们分别是公平锁和非公平锁了。

那公不公平的准则又是什么呢?

说到这个得先介绍一下CLH队列,CLH队列是AQS中“等待锁”的线程队列,比如说独占锁被一个线程占用着,其它线程就必须等待咯,这些线程就是在CLH队列等待的。这个队列的是用链表实现的,你可以看到AQS类有个内部类Node,这个就是链表的节点。CLH是通过自旋+CAS保证节点插入和移除的原子性(这个我在介绍原子类的时候说过类似的),就是说往里面插入或移除一个节点的时候,在并发条件下不会有问题。

至于CLH是什么意思,在Node的注释上有"CLH" (Craig, Landin, and Hagersten) lock queue,目测是三个人的名字缩写,应该是造出它的人吧。

那现在就可以回答公平的准则了。所谓公平,就是大家排队,是按照CLH队列先来先得的规则,即使锁没被任何线程持有,只要一个线程不是处于队头,它也会乖乖地等,公平地获取锁;非公平,那就是插队咯,当线程要获取锁时,它会无视CLH等待队列而直接获取锁,如果锁没有被任何线程持有,那不管它在CLH的那个角落,它都直接获取锁,没什么道德可言。

AbstractQueuedLongSynchronizer和AbstractOwnableSynchronizer

至于AbstractQueuedLongSynchronizer类跟AbstractQueuedSynchronizer类差不多,只不过它里面的statelong类型的,而AbstractQueuedSynchronizer的是int类型的,而且它们都继承了AbstractOwnableSynchronizer类——一个记录当前持有独占锁的线程的抽象类,这个类很简单,维护一个Thread类型变量,这个应该就是记录当前持有独占锁的线程,然后提供它的gettersetter方法,它虽然是一个抽象类,但是里面并没有抽象方法。

<think>好的,我现在要详细解释Java中的Lock接口和synchronized机制,同时结合用户提供的引用内容。首先,我需要明确用户的需求:他们想了解Lock接口的详细用法和实现,以及它synchronized的区别和各自的机制。 首先,根据引用[1]和[2],Lock接口是Java并发包的一部分,提供了比synchronized更灵活的控制。需要说明Lock的基本用法,比如lock()、unlock(),以及它的实现类如ReentrantLock。同时,对比synchronized,在引用[3]和[4]中提到synchronized的底层实现和优化,比如偏向、轻量级等,这些也需要涵盖进去。 接下来,用户可能希望了解两者的区别和适用场景。引用[2]指出Lock提供了更多控制方式,比如可中断、超时获取公平等,而synchronized是隐式获取和释放。需要详细对比这些特性,并给出使用示例。 然后,关于Lock接口的实现,需要解释其内部机制,比如AQS(AbstractQueuedSynchronizer),这是Java并发包中实现的基础。虽然引用中没有直接提到AQS,但结合知识,ReentrantLock是基于AQS实现的,应该补充这一点,但注意用户提供的引用中没有相关说明,所以可能需要避免超出引用范围。 对于synchronized的升级机制,引用[3]和[4]详细说明了偏向、轻量级、重量级的过程,需要分步骤解释,并结合jdk1.6后的优化措施。 还需要考虑代码示例,展示Lock和synchronized的具体使用方式,比如Lock的标准try-finally块,以及synchronized修饰方法或代码块。 最后,生成相关问题时要围绕两者的区别、使用场景、性能比较、升级机制等方面提问,确保问题具有针对性,帮助用户深入理解。 在组织内容时,需要保持结构清晰,分点讲解Lock和synchronized,再对比它们的区别,最后总结应用场景。同时,确保所有LaTeX格式正确,行内公式用$...$,独立公式用$$...$$,但当前内容可能较少涉及数学公式,需要检查是否有必要添加。 现在检查是否有遗漏的部分,比如Lock接口的具体方法,如tryLock()lockInterruptibly()等,以及Condition的使用,这些在引用中没有提到,但属于Lock接口的重要部分,需要包含进去。不过根据用户提供的引用,可能主要侧重于基本区别和机制,因此需要平衡详细度和引用内容。 总结,回答应包括: 1. Lock接口的用法和实现 2. synchronized的机制和优化 3. 两者的对比 4. 应用场景 5. 相关问题 确保每个部分都引用正确的来源,例如升级机制引用[3][4],Lock的优势引用[1][2]等。</think>### Lock接口synchronized机制详解 #### 一、Lock接口的用法实现 Lock接口是Java并发包(JUC)中定义的机制,提供比synchronized更灵活的控制方式。核心方法包括: - `lock()`:获取,若被占用则阻塞。 - `unlock()`:释放。 - `tryLock()`:尝试阻塞获取,成功返回`true`。 - `lockInterruptibly()`:可响应中断的获取。 **示例代码**: ```java Lock lock = new ReentrantLock(); lock.lock(); try { // 同步代码块 } finally { lock.unlock(); } ``` Lock的实现类如`ReentrantLock`支持**公平**和**公平**,通过构造参数指定。公平按等待顺序分配公平允许插队以提高吞吐量[^1][^2]。 #### 二、synchronized的机制优化 synchronized是JVM层面的内置,通过`monitorenter`和`monitorexit`指令实现。其升级机制(JDK 1.6+优化)包括: 1. **偏向**:首次访问时标记线程ID,后续直接进入同步代码块[^4]。 2. **轻量级**:当多线程竞争时,通过CAS操作尝试获取。 3. **重量级**:竞争激烈时升级为操作系统级别的Mutex Lock,涉及用户态到内核态的切换[^3]。 **示例代码**: ```java public synchronized void method() { // 同步方法 } // 或同步代码块 public void method() { synchronized(this) { // 同步区域 } } ``` #### 三、Locksynchronized的对比 | 特性 | Lock接口 | synchronized | |---------------------|-----------------------------------|-----------------------------| | **获取方式** | 显式调用`lock()`/`unlock()` | 隐式,通过代码块或方法修饰 | | **中断响应** | 支持`lockInterruptibly()` | 不支持 | | **超时机制** | 支持`tryLock(long time, TimeUnit unit)` | 不支持 | | **公平性** | 可配置公平公平 | 仅公平 | | **绑定多个条件** | 通过`Condition`实现多条件队列 | 仅一个等待队列 | | **性能** | 高竞争场景下更优 | 低竞争场景下优化更好 | #### 四、应用场景 - **synchronized**:适合简单的同步需求,如单线程占主导的低竞争场景。 - **Lock接口**:适合需要精细控制的场景,如超时、可中断公平等[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值