> 技术文档 > lock 和 synchronized 区别

lock 和 synchronized 区别


1. 引言

在多线程编程中,我们经常需要确保某些代码在同一时刻只由一个线程执行。这种机制通常叫做“互斥锁”或“同步”。Java 提供了两种主要的同步机制:synchronized 关键字和 Lock 接口。尽管它们的作用相似,都用于实现线程的同步,但在使用和功能上有一些显著的区别。

本文将详细对比 synchronizedLock,帮助理解它们的区别和各自的适用场景

2. synchronized 关键字

synchronized 是 Java 中实现线程同步的原生关键字,它的作用是确保某个方法或代码块在同一时刻只能由一个线程访问。synchronized 的语法相对简单,且直接嵌入到方法或代码块中。

2.1 基本用法

  • 同步方法:
public synchronized void someMethod() { // 临界区代码}
  • 同步代码块:
public void someMethod() { synchronized (this) { // 临界区代码 }}

2.2 特性

  • 隐式锁: synchronized 自动为被同步的方法或代码块加上锁,并在方法执行完后释放锁。
  • 不能中断: 在持有 synchronized 锁的线程执行过程中,其他线程不能中断该线程,除非该线程主动释放锁。
  • 只能锁住对象: 锁的对象是 JVM 中的对象引用,可以是 this,也可以是类对象(对于静态方法)。
  • 内置机制: synchronized 是 Java 的内置机制,在编译时由 JVM 自动管理。

3. Lock 接口

Lock 是 Java 提供的一个接口,定义在 java.util.concurrent.locks 包中,属于显式锁的实现。与 synchronized 相比,Lock 提供了更多的灵活性和控制,适合于更复杂的同步场景。

3.1 基本用法

Lock 的常用实现类是 ReentrantLock,使用时需要先创建 Lock 对象,然后手动获取和释放锁。

Lock lock = new ReentrantLock();public void someMethod() { lock.lock(); try { // 临界区代码 } finally { lock.unlock(); }}

3.2 特性

  • 显式锁:synchronized 不同,Lock 锁需要手动控制加锁和解锁。
  • 可中断: Lock 提供了带有中断响应的锁获取方法。例如,lock.lockInterruptibly() 允许在等待锁的时候响应中断。
  • 公平锁: ReentrantLock 提供了公平性选项,可以保证锁的获取按照请求锁的顺序进行(即先来先得)。
  • 可尝试锁: Lock 允许尝试获取锁,而不是一直等待,方法如 lock.tryLock() 可以尝试获取锁并返回是否成功。
  • 读写锁: Lock 还提供了 ReadWriteLock 接口,可以将锁分为读锁和写锁,提升多线程并发的性能。

4. synchronizedLock 的区别

4.1 锁的类型和粒度

  • synchronized 锁住的是对象(实例对象或类对象)。在方法上使用时,锁住的是方法所属的对象。
  • Lock 锁住的是一个显式的锁对象,通过 lock.lock() 方法来加锁,因此可以精确控制锁的范围。

4.2 控制粒度和灵活性

  • synchronized 锁的控制较为简单和粗糙,不能灵活控制线程的执行。
  • Lock 提供更多的控制方法(如 lockInterruptibly()tryLock()),支持中断、超时和公平性等特性,控制灵活。

4.3 锁的释放

  • synchronized 锁的释放是隐式的,在方法执行完后,JVM 自动释放锁,不需要显式地调用 unlock
  • Lock 锁的释放是显式的,必须手动调用 unlock(),否则可能导致死锁。

4.4 中断和超时

  • synchronized 无法响应中断,一旦进入同步代码块或方法,线程就会一直等待,直到获得锁。
  • Lock 提供了 lockInterruptibly() 方法,可以响应中断,线程可以在等待锁的过程中被中断。

4.5 性能和并发

  • synchronized 在高并发情况下,synchronized 的性能较差,尤其是锁竞争激烈时,容易导致性能瓶颈。
  • Lock 由于其更灵活的特性,Lock 在高并发下的表现往往优于 synchronized,尤其是在需要公平锁、尝试锁或读写锁的情况下。

5. 使用场景

5.1 使用 synchronized 的场景

  • 代码简洁,使用场景不复杂时,synchronized 是一个合适的选择。
  • 对于普通的互斥同步,使用 synchronized 更简洁,且由 JVM 自动管理锁。

5.2 使用 Lock 的场景

  • 需要更多控制的场景,如需要响应中断、尝试获取锁或实现公平锁时,Lock 是更好的选择。
  • 需要在同一方法中多次加锁并释放锁的场景,Lock 提供了更精细的控制。

6. 总结

特性 synchronized Lock 锁的类型 自动加锁,对象锁 显式加锁,可以是任何对象 锁的释放 自动释放,无法中断 必须手动释放,支持中断和超时 中断响应 不支持 支持 锁的公平性 不保证 可以选择公平锁 适用场景 代码简单的同步场景 高并发、需要更多控制的同步场景

通过对比可以看出,synchronized 适合简单的同步需求,而 Lock 更适合复杂的多线程控制和高并发场景。根据具体的需求选择合适的同步工具,能有效提高程序的效率和可维护性。