Synchronized 和 ReentrantLock 有什么区别?核心区别是什么?

在多线程并发开发中,线程间同步控制是重中之重。Java 语言为我们提供了多种锁机制,其中最常用的两种就是内置的 synchronized 关键字和 JDK 1.5 之后引入的 ReentrantLock。这两者虽然都能实现线程间的互斥与同步,但实现原理和使用方式却有所差异。那么它们之间究竟有哪些区别?开发时又该如何选择?本文将详细对比讲解。


一、synchronized 概述

synchronized 是 Java 的内置同步机制,占用 JVM 原语级别的支持。可以作用于方法或代码块,实现对对象/类的加锁,保证同一时间只有一个线程能访问被锁定的代码区域。

基本用法:

synchronized (lockObj) {
    // 临界区
}

或者:

public synchronized void foo() {
    // 同步方法
}

二、ReentrantLock 概述

ReentrantLock 是 JDK 1.5 提供的 Lock 接口实现,可重入互斥锁。其设计思想上与 synchronized 类似,但功能更灵活,扩展性更强,由 Java 代码实现(位于 java.util.concurrent.locks 包中)。

基本用法:

ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // 临界区
} finally {
    lock.unlock();
}

三、二者的主要区别

1. 底层实现

  • synchronized:依赖于 JVM 层实现,由 JVMmonitor monitorenter/monitorexit 指令维护锁的获取与释放。属于 JVM 内置锁。
  • ReentrantLock:完全由 Java 代码实现(基于AQS AbstractQueuedSynchronizer),可扩展。

2. 可重入性

两者均为可重入锁。同一线程可多次获取同一把锁。

3. 功能特性

特性synchronizedReentrantLock
可重入
公平锁×√(可指定公平/非公平)
支持中断×√(lockInterruptibly)
超时尝试加锁×√(tryLock)
条件变量×√(Condition实现等待通知)
手动释放锁×(自动)√(需 unlock() )
多锁支持×
死锁检测××
具体说明:
  1. 公平锁与非公平锁

    • ReentrantLock 可通过构造方法指定为“公平锁”,即先进先出获得锁。synchronized 总是非公平的。
  2. 可响应中断

    • ReentrantLock 支持可中断加锁(lockInterruptibly),即等待锁期间可以响应 interrupt 中断。
    • synchronized 无法响应中断,只能一直阻塞。
  3. 支持超时尝试加锁

    • ReentrantLock 的 tryLock(long timeout, TimeUnit unit) 支持超时等待。
    • synchronized 不支持超时。
  4. 支持多个条件变量

    • ReentrantLock 可创建多个 Condition,实现细粒度的 notify/wait 机制。
    • synchronized 只支持一个 monitor(wait/notifyAll)。
  5. 灵活释放锁

    • ReentrantLock 必须手动 unlock,容易遗漏(需配合 try-finally),但也更灵活。
    • synchronized 自动释放锁(出临界区自动释放)。

4. 性能表现

  • JDK1.6后,synchronized 经过锁优化(偏向锁、轻量级锁、自旋锁等),性能已大幅提升,无明显劣势。
  • ReentrantLock 适合需要特殊锁特性(如公平性、可中断、条件变量等)的场景。

四、核心区别总结

核心区别一句话总结
synchronized 是JVM层的“内置”锁,简单易用,不能灵活控制锁的高级特性;而 ReentrantLock 是Java代码实现的高级可重入锁,具有更多的配置和控制能力。

  • 【自动 vs 手动释放】—— synchronized 自动,ReentrantLock 需手动 unlock
  • 【功能维度】—— ReentrantLock 支持公平性、可中断性、超时和条件变量,synchronized 不支持
  • 【适用场景】—— 一般简单场景下用 synchronized,复杂并发控制下用 ReentrantLock

五、实际开发如何选择?

  1. 简单同步互斥:
    优先用 synchronized,语法简单,容易维护。

  2. 需要可中断/超时/公平/多条件变量等高级特性:
    选 ReentrantLock。

  3. 避免忘记释放锁出现死锁问题:
    synchronized 更保险(出错小)。

  4. 性能角度:
    JDK1.6 之后两者性能差异不大,大部分场景可优先 synchronized。


六、代码简单对比

synchronized:

public void syncMethod() {
    synchronized(this){
        // critical section
    }
}

ReentrantLock:

ReentrantLock lock = new ReentrantLock();
public void lockMethod() {
    lock.lock();
    try{
        // critical section
    } finally{
        lock.unlock();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值