Java synchronized与Lock的区别详解

在 Java 中,synchronized 关键字和 Lock 接口(如 ReentrantLock)都是用于实现线程同步的机制,但它们在设计、功能和灵活性上有显著区别。以下是主要区别的详细对比:


1. 实现机制

  • synchronized

    • 内置关键字:由 JVM 实现和管理,无需手动释放锁。
    • 自动释放:当线程执行完同步代码块或抛出异常时,JVM 会自动释放锁。
    • 示例
      public synchronized void method() {
          // 同步代码
      }
      // 或
      synchronized (obj) {
          // 同步代码块
      }
      
  • Lock

    • 接口实现:通过 java.util.concurrent.locks.Lock 接口(如 ReentrantLock)显式控制。
    • 手动管理:必须显式调用 lock() 加锁和 unlock() 释放锁(通常在 finally 块中确保释放)。
    • 示例
      Lock lock = new ReentrantLock();
      public void method() {
          lock.lock(); // 手动加锁
          try {
              // 同步代码
          } finally {
              lock.unlock(); // 必须手动释放
          }
      }
      

2. 功能特性

特性synchronizedLock
公平锁仅支持非公平锁支持公平锁(new ReentrantLock(true)
尝试非阻塞获取锁不支持tryLock() 立即返回成功/失败
超时获取锁不支持tryLock(long time, TimeUnit unit)
可中断等待锁不支持lockInterruptibly()
绑定多个条件变量不支持支持多个 Condition 队列

3. 条件等待(Condition)

  • synchronized
    使用 Object.wait()notify()notifyAll() 实现条件等待,但只能绑定一个隐式条件队列。
  • Lock
    通过 Condition 接口提供更灵活的条件控制:
    Condition condition = lock.newCondition();
    condition.await(); // 等待(类似 wait())
    condition.signal(); // 唤醒(类似 notify())
    
    可创建多个 Condition 实现精细化的线程分组唤醒(如生产者-消费者模型)。

4. 性能

  • Java 5 之前synchronized 性能较差(重量级锁)。
  • Java 6+:JVM 对 synchronized 进行了大量优化(偏向锁、轻量级锁、自旋锁等),性能接近 Lock
  • 高竞争场景Lock 可能仍优于 synchronized(如利用 tryLock 避免死锁)。

5. 锁的可重入性

  • 两者均支持:同一个线程可以重复获取同一把锁(避免自死锁)。

6. 异常处理

  • synchronized:自动释放锁,无资源泄漏风险。
  • Lock:需在 finally 中调用 unlock(),否则锁可能无法释放(导致死锁)。

7. 适用场景

  • 优先使用 synchronized
    简单同步需求,代码简洁性优先(JVM 自动管理)。
  • 选择 Lock
    需要高级功能(如公平锁、超时锁、可中断锁、多条件变量)或高竞争场景。

总结对比表

维度synchronizedLock
锁获取方式隐式(自动获取/释放)显式(手动 lock()/unlock()
灵活性较低高(支持多种锁获取策略)
公平锁不支持支持
条件变量单一等待队列Condition 队列
超时锁不支持支持
可中断锁阻塞时不可中断支持
代码复杂度简单(内置于语法)需手动管理(易漏 unlock()
性能趋势Java 6+ 优化后接近 Lock高竞争场景可能更优

代码示例对比

使用 synchronized
public class SyncExample {
    private int count = 0;
    
    public synchronized void increment() {
        count++; // 自动加锁/释放锁
    }
}
使用 Lock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    
    public void increment() {
        lock.lock(); // 显式加锁
        try {
            count++;
        } finally {
            lock.unlock(); // 必须显式释放
        }
    }
}

结论

  • 默认选择 synchronized:满足基础同步需求时,优先使用(简洁安全)。
  • 需要高级功能时用 Lock:如公平性、超时控制、可中断锁、多条件变量等场景。
    务必在 finally 中释放锁,避免死锁!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

走过冬季

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值