java之ReentrantLock

本文深入解析Java中的Lock接口与ReentrantLock实现原理,探讨显示锁与隐式锁的区别,以及AQS框架如何支撑多种锁机制。

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

Lock接口

Synchronized属于隐式锁,即锁的释放和获取都是隐式的。而我们接下来介绍的是显示锁Lock。JDK1.5中,在JAVA JUC包中添加了Lock接口,该接口提供了lock()方法和unlock()方法,以支持显示的加锁和解锁。需要注意的是unlock方法需要在finally中实现,不然会因为异常的出现导致各种并发问题。

public interface Lock {
    //加锁
    void lock();

    //解锁
    void unlock();

    //可中断获取锁,与lock()不同之处在于可响应中断操作,即在获
    //取锁的过程中可中断,注意synchronized在获取锁时是不可中断的
    void lockInterruptibly() throws InterruptedException;

    //尝试非阻塞获取锁,调用该方法后立即返回结果,如果能够获取则返回true,否则返回false
    boolean tryLock();

    //根据传入的时间段获取锁,在指定时间内没有获取锁则返回false,如果在指定时间内当前线程未被中并断获取到锁则返回true
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    //获取等待通知组件,该组件与当前锁绑定,当前线程只有获得了锁
    //才能调用该组件的wait()方法,而调用后,当前线程将释放锁。
    Condition newCondition();

可见Lock对象锁还提供了synchronized所不具备的其他同步特性,如可中断锁的获取(synchronized在等待获取锁时是不可中的),超时中断锁的获取,等待唤醒机制的多条件变量Condition等,这也使得Lock锁在使用上具有更大的灵活性。下面进一步分析Lock的实现类重入锁ReetrantLock。


可重入锁ReentrantLock

       重入锁ReentrantLock是Lock接口的具体实现类,JDK1.5中引入。ReentrantLock是一种支持重入的锁,即该锁支持一个线程对资源重复加锁,同时支持公平锁和非公平锁,所谓公平锁,即先对锁进行请求一定会先获取到锁。一般而言,非公平所效率高于公平锁。需要注意的是,ReentrantLock支持对同一资源重复加锁,但是加锁几次就需要解锁几次,这样才能成功释放锁。


并发组件AQS与ReentrantLock

一、AQS工作原理概要

       AQS(AbstractQueuedSynchronizer)又称为队列同步器,它是构建锁和其它同步组件的框架基础,内部通过一个int型成员变量state来控制同步状态,当status=0时,则说明没有任何线程持有该锁,当status=1时,则说明有线程目前正在访问共享变量,其它线程必须进入同步队列等待。AQS通过内部类Node构成FIFO的同步队列来完成获取锁的排队工作,同时利用内部类ConditionObject构建等待队列,当Condition调用wait方法后,线程将会进入等待队列中,而当Condition调用singal方法后,线程讲从等待队列转移到同步队列进行锁竞争。注意这里有两种队列,同步队列和等待队列,同步队列指线程试图获取锁而排队等待的队列;等待队列为线程通过Condition调用await方法释放锁后,进入的等待队伍。这里先研究AQS的同步队列模型:


        AQS同步器中有首尾指针,有status状态标识等等。其中头指针head指向头结点,不存储信息。而tail指向双链表末尾。其中Node结点为对每一个访问同步代码的线程的封装,从Node的数据结构可以看出(蓝色),Node包含了线程的状态,是否被阻塞,是否被等待唤醒,是否已经被取消,设置pre和next结点方便在释放锁后唤醒下一个正在等待的线程。

Node内部类结构如下

static final class Node {
    //共享模式
    static final Node SHARED = new Node();
    //独占模式
    static final Node EXCLUSIVE = null;

    //标识线程已处于结束状态
    static final int CANCELLED =  1;
    //等待被唤醒状态
    static final int SIGNAL    = -1;
    //条件状态,
    static final int CONDITION = -2;
    //在共享模式中使用表示获得的同步状态会被传播
    static final int PROPAGATE = -3;

    //等待状态,存在CANCELLED、SIGNAL、CONDITION、PROPAGATE 4种
    volatile int waitStatus;

    //同步队列中前驱结点
    volatile Node prev;

    //同步队列中后继结点
    volatile Node next;

    //请求锁的线程
    volatile Thread thread;

    //等待队列中的后继结点,这个与Condition有关,稍后会分析
    Node nextWaiter;

    //判断是否为共享模式
    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    //获取前驱结点
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    //.....
}

其中SHARED和EXCLUSIVE常量分别代表共享模式和独占模式,所谓共享模式即一个锁运行多个线程同时操作,如信号量Semaphore采用的就是AQS的共享模式实现,而独占模式就是同一时间段只能有一个线程对共享资源进行操作,如ReentrantLock。变量waitStatus则表示当前被封装成Node结点的线程状态,共有4中CANCLELLED,SINGAL,CONDITON,PROPAGATE。

CANCELLED;值为1,在同步队列中等待的线程等待超时或被中断,需要从Node队列中取消该Node结点,即结束状态,进入该状态的节点不会再变化。

SIGNAL:值为-1,被标识为等待唤醒状态的后继节点,当其结点的线程释放了同步锁或被取消,将会通知该后继结点线程执行。说白了就是备胎,就是处于唤醒状态,只要前继结点释放锁,就会通知标识为SINGAL状态的后继结点的线程执行。、

CONDITON:值为-2,与Condition相关,该标识的结点处于等待队列中,结点的线程等待在Condition上,当其他线程调用了Condition的Singal()方法后,Condition状态的结点又等待队列转移到同步队列,等待获取同步锁。

PROPAGATE:值为-3,与共享模式相关,在共享模式中,在该状态标识的节点的线程处于可运行状态。

0状态:值为0,代表初始化状态。




  • AbstractOwnableSynchronizer:抽象类,定义了存储独占当前锁的线程和获取的方法

  • AbstractQueuedSynchronizer:抽象类,AQS框架核心类,其内部以虚拟队列的方式管理线程的锁获取与锁释放,其中获取锁(tryAcquire方法)和释放锁(tryRelease方法)并没有提供默认实现,需要子类重写这两个方法实现具体逻辑,目的是使开发人员可以自由定义获取锁以及释放锁的方式。

  • Node:AbstractQueuedSynchronizer 的内部类,用于构建虚拟队列(链表双向链表),管理需要获取锁的线程。

  • Sync:抽象类,是ReentrantLock的内部类,继承自AbstractQueuedSynchronizer,实现了释放锁的操作(tryRelease()方法),并提供了lock抽象方法,由其子类实现。

  • NonfairSync:是ReentrantLock的内部类,继承自Sync,非公平锁的实现类。

  • FairSync:是ReentrantLock的内部类,继承自Sync,公平锁的实现类。

  • ReentrantLock:实现了Lock接口的,其内部类有Sync、NonfairSync、FairSync,在创建时可以根据fair参数决定创建NonfairSync(默认非公平锁)还是FairSync,ReentrantLock所有方法都通过间接调用AQS和Sync及其子类来实现。

       从上述类图可以看出AQS是一个抽象类,但请注意其源码中并没一个抽象的方法,这是因为AQS只是作为一个基础组件,并不希望直接作为直接操作类对外输出,而更倾向于作为基础组件,为真正的实现类提供基础设施,如构建同步队列,控制同步状态等,事实上,从设计模式角度来看,AQS采用的模板模式的方式构建的,其内部除了提供并发操作核心方法以及同步队列操作外,还提供了一些模板方法让子类自己实现,如加锁操作以及解锁操作,为什么这么做?这是因为AQS作为基础组件,封装的是核心并发操作,但是实现上分为两种模式,即共享模式与独占模式,而这两种模式的加锁与解锁实现方式是不一样的,但AQS只关注内部公共方法实现并不关心外部不同模式的实现,所以提供了模板方法给子类使用,也就是说实现独占锁,如ReentrantLock需要自己实现tryAcquire()方法和tryRelease()方法,而实现共享模式的Semaphore,则需要实现tryAcquireShared()方法和tryReleaseShared()方法,这样做的好处是显而易见的,无论是共享模式还是独占模式,其基础的实现都是同一套组件(AQS),只不过是加锁解锁的逻辑不同罢了,更重要的是如果我们需要自定义锁的话,也变得非常简单,只需要选择不同的模式实现不同的加锁和解锁的模板方法即可。

在了解了AQS后,我们来深入研究ReentrantLock:

ReentrantLock中非公平锁:

sync是个抽象类,这里来看其子类NofairSync的具体实现:

/**
 * 非公平锁实现
 */
static final class NonfairSync extends Sync {
    //加锁
    final void lock() {
        //执行CAS操作,获取同步状态
        if (compareAndSetState(0, 1))
       //成功则将独占锁线程设置为当前线程  
          setExclusiveOwnerThread(Thread.currentThread());
        else
            //否则再次请求同步状态
            acquire(1);
    }
}

在获取同步状态时,首先对同步状态进行CAS操作,尝试把status由0设置为1,如果返回true则表示获取同步状态成功,也就是当前线程获取锁成功,如果返回false,则表示已存在线程获取了该同步状态,获取锁失败。返回false后执行acquire(1)方法,这个方法是AQS中的方法,它对中断不敏感,即使线程获取同步状态失败,进入同步队列,后续对该线程执行中断操作也不会从同步队列移出。

即获取失败后进入AQS同步队列。


这是默认不可中断的获取锁操作。

下面介绍的是可中断的获取锁操作:

可以通过调用ReentrantLock的lockInterrputibly()或者tryLock()方法实现,最终它们都会调用doAcquireInterrputibly()方法

和不可中断获取锁最大的不同在于,在同步队列自旋过程中,若检测到线程的中断状态后直接抛出InterruptedException异常中断线程,并移出同步队列。

OK,加锁流程到此结束,下面来看一下解锁unlock()操作。

在释放同步状态时,则通过调用子类(ReetrantLock中的Sync内部类)的tryRelease(int releases)方法释放同步状态,释放成功则唤醒后继结点的线程。

ReentrantLock中公平锁:

在获取锁方法lock()中,该方法与nonfairTryAcquire(int acquires)方法唯一的不同是在使用CAS设置尝试设置state值前,调用了hasQueuedPredecessors()判断同步队列是否存在结点,如果存在必须先执行完同步队列中结点的线程,当前线程进入等待状态。这就是非公平锁与公平锁最大的区别,即公平锁在线程请求到来时先会判断同步队列是否存在结点,如果存在先执行同步队列中的结点线程,当前线程将封装成node加入同步队列等待。而非公平锁呢,当线程请求到来时,不管同步队列是否存在线程结点,直接尝试获取同步状态,获取成功直接访问共享资源,但请注意在绝大多数情况下,非公平锁才是我们理想的选择,毕竟从效率上来说非公平锁总是胜于公平锁。 

  以上便是ReentrantLock的内部实现原理,这里我们简单进行小结,重入锁ReentrantLock,是一个基于AQS并发框架的并发控制类,其内部实现了3个类,分别是Sync、NoFairSync以及FairSync类,其中Sync继承自AQS,实现了释放锁的模板方法tryRelease(int),而NoFairSync和FairSync都继承自Sync,实现各种获取锁的方法tryAcquire(int)。ReentrantLock的所有方法实现几乎都间接调用了这3个类,因此当我们在使用ReentrantLock时,大部分使用都是在间接调用AQS同步器中的方法,这就是ReentrantLock的内部实现原理。

关于synchronized 与ReentrantLock

在JDK 1.6之后,虚拟机对于synchronized关键字进行整体优化后,在性能上synchronized与ReentrantLock已没有明显差距,因此在使用选择上,需要根据场景而定,大部分情况下我们依然建议是synchronized关键字,原因之一是使用方便语义清晰,二是性能上虚拟机已为我们自动优化。而ReentrantLock提供了多样化的同步特性,如超时获取锁、可以被中断获取锁(synchronized的同步是不能中断的)、等待唤醒机制的多个条件变量(Condition)等,因此当我们确实需要使用到这些功能是,可以选择ReentrantLock。

关于Condition接口

在并发编程中,每个Java对象都存在一组监视器方法,如wait()notify()以及notifyAll()方法,通过这些方法,我们可以实现线程间通信与协作(也称为等待唤醒机制),如生产者-消费者模式,而且这些方法必须配合着synchronized关键字使用,

与synchronized的等待唤醒机制相比Condition具有更多的灵活性以及精确性,这是因为notify()在唤醒线程时是随机(同一个锁),而Condition则可通过多个Condition实例对象建立更加精细的线程控制,也就带来了更多灵活性了,我们可以简单理解为以下两点

  • 通过Condition能够精细的控制多线程的休眠与唤醒。

  • 对于一个锁,我们可以为多个线程间建立不同的Condition。

Condition是一个接口类,其主要方法如下:


public interface Condition {

 /**
  * 使当前线程进入等待状态直到被通知(signal)或中断
  * 当其他线程调用singal()或singalAll()方法时,该线程将被唤醒
  * 当其他线程调用interrupt()方法中断当前线程
  * await()相当于synchronized等待唤醒机制中的wait()方法
  */
 void await() throws InterruptedException;

 //当前线程进入等待状态,直到被唤醒,该方法不响应中断要求
 void awaitUninterruptibly();

 //调用该方法,当前线程进入等待状态,直到被唤醒或被中断或超时
 //其中nanosTimeout指的等待超时时间,单位纳秒
 long awaitNanos(long nanosTimeout) throws InterruptedException;

  //同awaitNanos,但可以指明时间单位
  boolean await(long time, TimeUnit unit) throws InterruptedException;

 //调用该方法当前线程进入等待状态,直到被唤醒、中断或到达某个时
 //间期限(deadline),如果没到指定时间就被唤醒,返回true,其他情况返回false
  boolean awaitUntil(Date deadline) throws InterruptedException;

 //唤醒一个等待在Condition上的线程,该线程从等待方法返回前必须
 //获取与Condition相关联的锁,功能与notify()相同
  void signal();

 //唤醒所有等待在Condition上的线程,该线程从等待方法返回前必须
 //获取与Condition相关联的锁,功能与notifyAll()相同
  void signalAll();
}
关于Condition的实现类是AQS的内部类ConditionObject

Condition的实现原理

Condition的具体实现类是AQS的内部类ConditionObject,前面我们分析过AQS中存在两种队列,一种是同步队列,一种是等待队列,而等待队列就相对于Condition而言的。注意在使用Condition前必须获得锁,同时在Condition的等待队列上的结点与前面同步队列的结点是同一个类即Node,其结点的waitStatus的值为CONDITION。在实现类ConditionObject中有两个结点分别是firstWaiter和lastWaiter,firstWaiter代表等待队列第一个等待结点,lastWaiter代表等待队列最后一个等待结点,如下

 public class ConditionObject implements Condition, java.io.Serializable {
    //等待队列第一个等待结点
    private transient Node firstWaiter;
    //等待队列最后一个等待结点
    private transient Node lastWaiter;
    //省略其他代码.......
}

每个Condition都对应着一个等待队列,也就是说如果一个锁上创建了多个Condition对象,那么也就存在多个等待队列。等待队列是一个FIFO的队列,在队列中每一个节点都包含了一个线程的引用,而该线程就是Condition对象上等待的线程。当一个线程调用了await()相关的方法,那么该线程将会释放锁,并构建一个Node节点封装当前线程的相关信息加入到等待队列中进行等待,直到被唤醒、中断、超时才从队列中移出。Condition中的等待队列模型如下

正如图所示,Node节点的数据结构,在等待队列中使用的变量与同步队列是不同的,Condtion中等待队列的结点只有直接指向的后继结点并没有指明前驱结点,而且使用的变量是nextWaiter而不是next,这点我们在前面分析结点Node的数据结构时讲过。firstWaiter指向等待队列的头结点,lastWaiter指向等待队列的尾结点,等待队列中结点的状态只有两种即CANCELLED和CONDITION,前者表示线程已结束需要从等待队列中移除,后者表示条件结点等待被唤醒。再次强调每个Codition对象对于一个等待队列,也就是说AQS中只能存在一个同步队列,但可拥有多个等待队列。下面从代码层面看看被调用await()方法(其他await()实现原理类似)的线程是如何加入等待队列的,而又是如何从等待队列中被唤醒的

awati()等待方法:

await()方法主要做了3件事,一是调用addConditionWaiter()方法将当前线程封装成node结点加入等待队列,二是调用fullyRelease(node)方法释放同步状态并唤醒后继结点的线程。三是调用isOnSyncQueue(node)方法判断结点是否在同步队列中,注意是个while循环,如果同步队列中没有该结点就直接挂起该线程,需要明白的是如果线程被唤醒后就调用acquireQueued(node, savedState)执行自旋操作争取锁,即当前线程结点从等待队列转移到同步队列并开始努力获取锁。

signal唤醒方法:

这里signal()方法做了两件事,一是判断当前线程是否持有独占锁,没有就抛出异常,从这点也可以看出只有独占模式先采用等待队列,而共享模式下是没有等待队列的,也就没法使用Condition。二是唤醒等待队列的第一个结点,即执行doSignal(first)



<think>我们正在讨论的是ReentrantLock的使用场景。根据引用[1][3][4][5],ReentrantLock是一个灵活的锁机制,提供了比synchronized更多的控制选项。下面我将详细分析其适用场景。 1. **需要可中断锁的场景** 当线程在等待锁的过程中,如果希望可以响应中断(比如等待时间过长需要取消操作),ReentrantLock的`lockInterruptibly()`方法提供了这种能力[^3][^5]。 - 示例:在分布式任务调度中,如果一个任务长时间等待锁,可以通过中断机制取消该任务,避免无限期阻塞。 2. **需要公平锁的场景** ReentrantLock可以创建公平锁(通过构造函数设置`fair=true`),保证等待时间最长的线程优先获取锁[^2][^4]。 - 适用场景:金融交易系统、订票系统等需要严格顺序执行的操作,避免线程饥饿问题。 3. **需要尝试获取锁(非阻塞或超时)的场景** ReentrantLock提供了`tryLock()`方法,支持立即返回或设置超时时间[^3][^5]。 - 示例: ```java if (lock.tryLock(3, TimeUnit.SECONDS)) { // 尝试在3秒内获取锁 try { // 操作共享资源 } finally { lock.unlock(); } } else { // 执行备选方案 } ``` - 适用场景:高并发服务中,避免因锁竞争导致系统假死(如电商秒杀库存更新时,快速失败降级处理)。 4. **需要绑定多个条件的场景** ReentrantLock可以创建多个`Condition`对象,实现精细化的线程等待/唤醒控制[^1][^4]。 - 示例:生产者-消费者模型中,为队列满和队列空分别设置条件: ```java ReentrantLock lock = new ReentrantLock(); Condition notFull = lock.newCondition(); // 队列未满条件 Condition notEmpty = lock.newCondition(); // 队列非空条件 // 生产者线程 lock.lock(); try { while (queue.isFull()) { notFull.await(); // 等待队列不满 } queue.add(item); notEmpty.signal(); // 唤醒消费者 } finally { lock.unlock(); } ``` - 适用场景:线程池任务队列、消息中间件等需要多条件协作的复杂同步逻辑。 5. **需要可重入锁且synchronized无法满足的场景** 虽然synchronized也是可重入的,但ReentrantLock在以下情况更优[^5]: - 跨方法释放锁(synchronized必须在单个方法块内释放); - 需要锁的细粒度控制(如锁分段技术); - 需要结合其他高级并发工具(如ReadWriteLock)。 #### 与synchronized的对比选择[^5] | **场景** | **推荐选择** | |------------------------------|--------------------| | 简单同步(如单方法块保护) | synchronized | | 需中断、超时、公平锁等特性 | ReentrantLock | | 高竞争环境下(性能敏感) | 根据JDK版本测试选择 | > **注意**:JDK 6后synchronized经过优化(锁升级),在低竞争场景性能接近ReentrantLock[^5],但复杂控制仍需ReentrantLock。 #### 总结 ReentrantLock适用于以下五类场景: 1. **可中断锁**(避免死等) 2. **公平锁**(保证顺序性) 3. **尝试锁**(快速失败/超时控制) 4. **多条件变量**(精细线程协作) 5. **复杂锁控制**(超越synchronized能力) 在业务系统中(如引用[4]提到的电商库存管理),这些特性对高并发下的资源保护至关重要[^4]。 §§相关问题§§ 1. ReentrantLock的公平锁和非公平锁在性能上有何差异? 2. 如何避免ReentrantLock忘记调用`unlock()`导致死锁? 3. ReentrantLock与StampedLock的适用场景对比? 4. 在分布式系统中,ReentrantLock能否替代分布式锁?</think>### Java ReentrantLock适用场景分析 ReentrantLockJava并发中提供的显式锁机制,相比synchronized关键字,它提供了更精细的锁控制能力。以下是其核心适用场景及分析: --- #### 1. **需要公平锁的场景** 当需要**保证线程获取锁的顺序性**(FIFO)时,应使用ReentrantLock的公平锁模式[^2][^4]。 ```java ReentrantLock fairLock = new ReentrantLock(true); // true表示公平锁 ``` - **适用场景**: - 金融交易系统:保证交易请求按到达顺序处理 - 票务系统:防止高并发下资源分配不公 - 任务调度:确保长时间等待的线程优先执行 - **优势**:避免线程饥饿问题,提供可预测的锁获取顺序 --- #### 2. **需要锁超时/中断的场景** 当需要**限制锁等待时间**或**响应线程中断**时,应使用ReentrantLock的`tryLock()`方法[^3][^5]: ```java if (lock.tryLock(3, TimeUnit.SECONDS)) { // 尝试获取锁,最多等待3秒 try { // 临界区操作 } finally { lock.unlock(); } } else { // 执行备选方案(如降级策略) } ``` - **适用场景**: - 高并发服务:防止线程死等导致系统假死 - 实时系统:确保操作在限定时间内完成 - 分布式系统协调:配合熔断机制使用 - **优势**:避免死锁,提高系统健壮性 --- #### 3. **需要多条件变量的场景** 当需要**基于不同条件阻塞/唤醒线程**时,应使用ReentrantLock的`Condition`对象[^1][^4]: ```java Condition notFull = lock.newCondition(); Condition notEmpty = lock.newCondition(); // 生产者线程 lock.lock(); try { while (queue.isFull()) { notFull.await(); // 等待"非满"条件 } // 生产操作... notEmpty.signal(); // 唤醒消费者 } finally { lock.unlock(); } ``` - **适用场景**: - 生产者-消费者模型 - 线程池任务队列管理 - 资源池(如数据库连接池) - **优势**:比`synchronized+wait()/notifyAll()`更精细的线程协作控制 --- #### 4. **需要可中断锁的场景** 当需要**响应线程中断信号**时,使用`lockInterruptibly()`[^3][^5]: ```java try { lock.lockInterruptibly(); // 可响应中断的加锁 // ... } catch (InterruptedException e) { // 处理中断逻辑 } finally { if (lock.isHeldByCurrentThread()) lock.unlock(); } ``` - **适用场景**: - 取消长时间等待的操作 - 服务优雅停机 - 响应式系统 - **优势**:避免线程因锁等待无法响应中断 --- #### 5. **需要跨方法释放锁的场景** 当**锁的获取和释放需要在不同方法中完成**时,ReentrantLock比synchronized更灵活[^4][^5]: ```java public void methodA() { lock.lock(); try { // ... methodB(); // 嵌套调用 } finally { lock.unlock(); } } public void methodB() { // 无需重复加锁(可重入特性) } ``` - **适用场景**: - 复杂事务处理 - 递归算法实现 - 分层锁设计 - **优势**:保持锁状态一致性,避免嵌套锁问题 --- #### 6. **与synchronized的对比选择** | 特性 | ReentrantLock | synchronized | |-----------------------|-----------------------------------|----------------------------| | 锁获取方式 | 显式(`lock()/unlock()`) | 隐式(代码块) | | 公平锁支持 | ✅ (构造函数指定) | ❌ | | 锁超时 | ✅ (`tryLock()`) | ❌ | | 条件变量 | ✅ (多Condition支持) | ❌ (单条件) | | 可中断锁 | ✅ (`lockInterruptibly()`) | ❌ | | 性能(JDK17+) | 接近 | 接近 | | 内存语义 | 更清晰的happens-before关系[^2] | JVM自动管理 | > **决策树**: > ```mermaid > graph TD > A[需要锁控制?] --> B{简单同步} > A --> C{复杂需求} > B --> D[使用synchronized] > C --> E{需要公平锁/超时/多条件?} > E -->|是| F[选择ReentrantLock] > E -->|否| D > ``` --- #### 典型业务场景示例 1. **电商库存扣减** 使用`tryLock()`实现限时库存操作,超时返回"库存繁忙"[^4] ```java if (inventoryLock.tryLock(100, TimeUnit.MILLISECONDS)) { try { // 库存检查与扣减 } finally { inventoryLock.unlock(); } } else { throw new BusyException("系统繁忙"); } ``` 2. **多条件任务调度** 使用双Condition实现任务队列管理[^1]: ```java // 任务队列满时阻塞提交,空时阻塞获取 Condition notFull = lock.newCondition(); Condition notEmpty = lock.newCondition(); ``` 3. **金融交易顺序处理** 公平锁保证交易按时间顺序执行[^2]: ```java ReentrantLock tradeLock = new ReentrantLock(true); // 公平锁 ``` --- ### 总结 优先选择**ReentrantLock**当遇到以下需求: ✅ 需要公平锁机制 ✅ 需要锁超时或中断响应 ✅ 需要多条件变量协作 ✅ 需要跨方法控制锁生命周期 ✅ 需要清晰的锁行为诊断(如`getQueuedThreads()`) 优先选择**synchronized**当: ✅ 简单的同步块(代码更简洁) ✅ 性能敏感且无高级需求(现代JVM优化充分) ✅ 不需要精细锁控制[^5] > 在Java 17+中,两者性能差距已显著缩小,选择应基于功能需求而非性能预设[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值