ReentrantLock与synchronized区别

发布于:2025-08-19 ⋅ 阅读:(45) ⋅ 点赞:(0)

目录

一、核心功能与特性

二、性能对比

三、使用方式

四、典型代码示例

1. synchronized的使用

2. ReentrantLock的使用

五、总结


ReentrantLock(可重入锁)和synchronized是Java中实现线程同步的两种核心机制,

一、核心功能与特性

对比维度

synchronized

ReentrantLock

实现方式

关键字,由JVM底层实现(C++代码)

类(java.util.concurrent.locks包),API层面实现

可重入性

支持(同一线程可多次获取同一把锁,自动记录重入次数)

支持(通过getHoldCount()可获取重入次数)

锁释放

自动释放(同步块/方法执行完毕或异常时)

手动释放(必须在finally块中调用unlock(),否则可能导致死锁)

锁类型

非公平锁(默认),无法切换为公平锁

可通过构造函数指定公平/非公平锁(new ReentrantLock(true)为公平锁)

中断响应

不支持(线程获取锁时,无法被中断,会一直阻塞)

支持(通过lockInterruptibly(),可响应中断,避免无限等待)

超时获取

不支持(获取不到锁会一直阻塞)

支持(tryLock(long timeout, TimeUnit unit),超时未获取则返回false

条件变量

不支持(仅能通过对象的wait()/notify()机制)

支持(通过newCondition()创建Condition对象,可实现更灵活的等待/唤醒逻辑,如多条件队列)

锁状态查询

无法直接查询

可查询(isLocked()判断是否被锁,isHeldByCurrentThread()判断当前线程是否持有锁等)

锁实现机制

Monitor(监视器)

AQS 同步框架

二、性能对比

  1. JDK 6之前synchronized性能较差(存在重量级锁的优化不足),ReentrantLock性能更优。
  2. JDK 6及之后:JVM对synchronized进行了大量优化(如偏向锁、轻量级锁、锁消除、锁粗化等),两者性能差异不大,在多数场景下synchronized甚至更优(JVM对其优化更深入)。

三、使用方式

场景

推荐选择

原因

简单的同步代码块/方法

synchronized

语法简洁,无需手动释放锁,不易出错,JVM优化充分。

需要公平锁机制

ReentrantLock

可通过构造函数指定公平锁,保证线程获取锁的顺序(按等待时间排序)。

需要中断等待锁的线程

ReentrantLock

lockInterruptibly()支持中断,避免线程无限阻塞。

需要超时获取锁

ReentrantLock

tryLock()可设置超时时间,防止死锁。

需要多条件等待/唤醒

ReentrantLock

Condition支持多条件队列,可精准唤醒特定线程(synchronizednotify()随机唤醒)。

需要查询锁状态

ReentrantLock

提供多种方法查询锁状态,便于调试和监控。

资源竞争激烈的高并发场景

两者均可(视情况)

JDK 6+后性能接近,synchronized更省心,ReentrantLock功能更灵活。

四、典型代码示例

1. synchronized的使用
// 同步方法
public synchronized void syncMethod() {
    // 同步逻辑
}

// 同步代码块
public void syncBlock() {
    synchronized (this) {
        // 同步逻辑
    }
}
2. ReentrantLock的使用
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private final ReentrantLock lock = new ReentrantLock(); // 非公平锁(默认)
    // private final ReentrantLock lock = new ReentrantLock(true); // 公平锁

    public void lockMethod() {
        lock.lock(); // 获取锁
        try {
            // 同步逻辑
        } finally {
            lock.unlock(); // 必须在finally中释放锁
        }
    }

    // 超时获取锁
    public boolean tryLockWithTimeout() throws InterruptedException {
        if (lock.tryLock(1, TimeUnit.SECONDS)) { // 1秒超时
            try {
                // 同步逻辑
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }
}

五、总结

  1. synchronized的优势:语法简单、自动释放锁、不易出错、JVM优化成熟,适合大多数基础同步场景。
  2. ReentrantLock的优势:功能更灵活(公平锁、中断、超时、多条件),适合复杂同步场景,需手动管理锁释放(注意finally块)。

网站公告

今日签到

点亮在社区的每一天
去签到