java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java synchronized与ReentrantLock

Java中synchronized和ReentrantLock的区别对比

作者:程序员小假

这篇文章主要介绍了Java中synchronized和ReentrantLock的区别对比,synchronized和ReentrantLock是Java中两种主要的线程同步机制,它们都能保证线程安全,但在实现和功能上有明显区别,需要的朋友可以参考下本篇介绍

一、基本特性对比

特性synchronizedReentrantLock
锁的实现机制JVM 内置关键字,通过监视器实现JDK 提供的 API 类(java.util.concurrent.locks)
锁的获取方式隐式获取和释放(进入/退出同步代码块或方法自动获取/释放)显式调用 lock()/unlock()方法
可重入性支持支持
锁的类型非公平锁(默认)可选择公平锁或非公平锁(构造函数指定)
条件变量通过 wait()/notify()/notifyAll()实现通过 Condition对象支持多个条件队列
中断响应不支持中断等待支持 lockInterruptibly()中断等待
超时机制不支持支持 tryLock(timeout, unit)尝试获取锁
锁的绑定与代码块或方法绑定可跨方法绑定,更灵活
性能JDK 1.6 后优化,性能接近在高并发竞争下表现更稳定

二、详细区别分析

1. 实现层面

synchronized:

ReentrantLock:

2. 使用方式

// synchronized 隐式使用
public synchronized void method() {
    // 同步代码
}
// 或
public void method() {
    synchronized(this) {
        // 同步代码
    }
}
// ReentrantLock 显式使用
private ReentrantLock lock = new ReentrantLock();
public void method() {
    lock.lock();
    try {
        // 同步代码
    } finally {
        lock.unlock(); // 必须手动释放
    }
}

3. 公平性选择

synchronized:仅支持非公平锁(线程竞争时随机获取锁)。

ReentrantLock:

4. 条件变量(Condition)

Condition condition = lock.newCondition();
condition.await();      // 类似 wait()
condition.signal();     // 类似 notify()

示例:生产者-消费者模型中,可为空队列和满队列分别设置 Condition。

5. 中断与超时

synchronized:

ReentrantLock:

// 支持中断
lock.lockInterruptibly();
// 支持超时
if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try { /* 操作 */ } 
    finally { lock.unlock(); }
}

6. 性能差异

三、适用场景

优先使用 synchronized 的情况

优先使用 ReentrantLock 的情况

四、示例对比

场景:生产者-消费者模型

// 使用 synchronized(单一条件)
public synchronized void put(Object item) throws InterruptedException {
    while (queue.isFull()) {
        wait(); // 只能在一个条件上等待
    }
    queue.put(item);
    notifyAll();
}
// 使用 ReentrantLock(多条件)
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public void put(Object item) throws InterruptedException {
    lock.lock();
    try {
        while (queue.isFull()) {
            notFull.await(); // 只在 "非满" 条件上等待
        }
        queue.put(item);
        notEmpty.signal();   // 只唤醒等待 "非空" 的线程
    } finally {
        lock.unlock();
    }
}

五、总结

面试回答

首先,synchronized 是 Java 语言层面的关键字,是 JVM 原生支持的锁机制。它的使用非常简单,编译器会自动处理锁的获取和释放,所以基本不会因为忘记释放锁而导致死锁,易用性是它的最大优点。

而 ReentrantLock 是 JUC 包下的一个类,是 JDK 层面实现的锁。它需要开发者显式地调用 lock() 和 unlock() 方法,通常在 finally 块中释放锁,否则容易出问题。所以从使用门槛上说,synchronized 更低。

在功能上,ReentrantLock 比 synchronized 灵活和强大得多,主要有三点:

在早期版本(JDK 1.5 之前),ReentrantLock 的性能比 synchronized 好很多。但后来 JVM 对 synchronized 进行了大幅优化,比如引入了偏向锁、轻量级锁、自旋锁、锁消除、锁粗化等。所以在高版本的 JDK(如 1.8 及以后)中,两者在性能上已经相差无几,synchronized 甚至在一些常见场景下更优,因为它有 JVM 的持续优化。

所以,我的选择原则通常是:

以上就是Java中synchronized和ReentrantLock的区别对比的详细内容,更多关于Java synchronized与ReentrantLock的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文