ReentrantLock详解(定义原理及使用场景)

ReentrantLock详解(定义原理及使用场景)-mikechen

ReentrantLock是Java线程同步的一种方式,在Java多线程编程经常用到,下面重点来详解ReentrantLock@mikechen

ReentrantLock定义

ReentrantLock是Java中的一个可重入锁,是一种比synchronized更加灵活和强大的同步机制。

 

ReentrantLock组成

ReentrantLock详解(定义原理及使用场景)-mikechen

通过上图的继承关系,我们都能大概梳理出ReentrantLock的处理逻辑。

内部定义了三个重要的静态内部类:Sync,NonFairSync,FairSync

  • Sync作为ReentrantLock中公用的同步组件,继承了AQS(要利用AQS来实现线程排队,阻塞,唤醒等等)
  • NonfairSync(非公平锁) 继承 Sync 抽象类
  • FairSync(公平锁) 继承 Sync 抽象类

 

ReentrantLock原理

在具体实现上,ReentrantLock是基于AQS来实现,AQS全名:AbstractQueuedSynchronizer,AQS是一个用于实现同步器的类。

除了ReentrantLock基于AQS,还有Semaphore、CountDownLatch等的底层实现方式也是基于AQS来实现。

AQS它实现了一个FIFO的队列,底层实现的数据结构是一个双向链表,如下图所示:

ReentrantLock详解(定义原理及使用场景)-mikechen

AQS维护了一个状态变量state,用于表示锁的状态,以及一个线程变量exclusiveOwnerThread,用于记录当前持有锁的线程。

具体实现,大致分为如下几点:

  1. ReentrantLock在调用lock()方法时,会首先判断当前线程是否已经持有锁;
  2. 如果是,则将锁的重入次数加1,并返回;
  3. 否则,将当前线程加入到等待队列中,等待获取锁。

 

 

ReentrantLock使用

下面是一个简单的使用ReentrantLock的示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
    private Lock lock = new ReentrantLock(); // 创建一个ReentrantLock对象

    public void print() {
        lock.lock(); // 获取锁
        try {
            System.out.println(Thread.currentThread().getName() + " is printing.");
            Thread.sleep(1000); // 模拟打印操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public static void main(String[] args) {
        final ReentrantLockDemo demo = new ReentrantLockDemo();

        // 创建多个线程并启动
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                demo.print();
            }, "Thread-" + i).start();
        }
    }
}

我们创建了一个ReentrantLock对象,并在print()方法中使用了lock()和unlock()方法来获取和释放锁。

由于只有一个ReentrantLock对象,因此在同一时刻只有一个线程可以执行print()方法,其他线程需要等待该线程释放锁后才能获取锁并执行print()方法。

 

ReentrantLock应用

ReentrantLock适用于需要高度控制的并发环境,其应用场景包括但不限于以下5种:

  1. 需要实现公平或非公平的锁机制:ReentrantLock可以设置公平或非公平锁,以满足不同的需求。
  2. 需要限制等待锁的时间:ReentrantLock可以设置等待锁的时间,如果等待时间超过设定值,等待的线程就可以自动放弃锁的获取。
  3. 需要使用条件变量:ReentrantLock可以使用Condition对象来实现多个条件变量,可以更加精细地控制线程的等待和通知。
  4. 需要避免死锁:由于ReentrantLock支持可重入性,同一个线程可以多次获取同一把锁,这可以避免死锁的发生。
  5. 需要精确控制锁的释放:使用synchronized关键字时,锁的释放是由JVM自动控制的,而使用ReentrantLock可以手动控制锁的释放,以达到更精确的控制效果。

以上就是ReentrantLock的详解,更多Java线程锁,请查看:4种常用Java线程锁的特点,性能比较、使用场景

陈睿mikechen

10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

关注「mikechen」公众号,获取更多技术干货!

后台回复面试即可获取《史上最全阿里Java面试题总结》,后台回复架构,即可获取《阿里架构师进阶专题全部合集

评论交流
    说说你的看法