Java 并发中 Lock 和 Monitor 的区别

2024年9月10日 | 阅读 6 分钟

Lock

Java 中的 Lock 是同步原语,用于控制对共享资源或代码关键部分的访问,以确保一次只有一个线程可以访问它们。

Lock 是一种简单的同步构造,允许一个线程获取资源的锁。一旦一个线程获取了资源的锁,第一个线程在释放锁之后,其他线程就可以再次获取该锁。

Lock 确保一次只有一个线程可以访问受保护的资源,从而防止了竞态条件和数据损坏。

Java 提供了几种实现 Lock 的机制,其中最常用的是来自java.util.concurrent.locks包的 'ReentrantLock' 类。以下是 Java 并发中 Lock 的概述:

1. ReentranLock

Java 中的ReentrantLock是一种同步机制,它允许线程多次获取同一个锁而不会阻塞自身。当线程需要访问由锁保护的共享资源时,它非常有用。

ReentrantLock 提供了多种锁定和解锁方法,包括 lock()、unlock()、tryLock() 和 newCondition()。

与 synchronized 块或方法相比,它提供了更细粒度的同步控制。

ReentrantLockExample.java

输出

Thread 1 is performing a task.
Thread 1 has completed the task.
Thread 2 is performing a task.
Thread 2 has completed the task.

在此示例中,doSomething() 方法在访问共享资源之前获取锁。当方法完成对资源的访问后,它会释放锁。

2. Lock 接口

Java 提供了各种 Lock 接口,例如 Lock、ReadWriteLock 和 Condition,使我们能够为特定的并发需求选择合适的 Lock 类型。

3. 异常处理

Lock 应在 try-finally 块中使用,以确保即使发生异常也能正确释放锁。

重要的是要防止资源泄露,并确保当前线程完成后,其他线程可以访问被锁定的资源。

4. 并发集合

java.util.concurrent 包中的许多类在内部使用 Lock 来提供线程安全集合,例如 ConcurrentHashMap 和 CopyOnWriteArrayList。

Monitor

在 Java 并发中,Monitor 是一种与对象和方法关联的同步概念。它提供了多线程的基本要求。

Monitor 是一种同步机制,它允许线程拥有

互斥性 - 在同一时间只有一个线程可以执行该方法,使用锁。

协作 - 使用 wait-set 使线程等待某些条件满足的能力。

Monitor 主要“监视”线程之间对共享资源和对象的访问控制。

1. 同步方法

我们可以将 Java 中的方法声明为 synchronized,使其成为同步方法。当线程进入同步方法时,它会获取与对象实例关联的 Monitor。

2. 同步块

除了同步方法,我们还可以使用同步块来保护代码的特定部分。它允许更细粒度的同步控制。

SynchronisedBlockExample.java

输出

Final Count: 0

3. 内置锁

在 Java 中,每个对象都有一个内置锁,也称为 Monitor 锁。它允许线程获取对对象的独占访问。这意味着在同一时间只有一个线程可以执行对该对象进行同步的代码。内置锁用于防止竞态条件。

要获取内置锁,线程会调用 synchronized() 方法。synchronized() 方法将一个对象作为其参数。然后线程获取该对象的内置锁。一旦线程获取了锁,它就可以执行同步代码,而无需担心其他线程的干扰。

当线程完成同步代码的执行后,它必须释放内置锁。线程再次调用 synchronized() 方法,这次带有 false 参数。false 参数告诉 synchronized() 方法释放锁。

IntrinsicLockExample.java

输出

Thread 1 is performing a synchronized task.
Thread 1 has completed the task.
Thread 2 is performing a synchronized task.
Thread 2 has completed the task.

4. 确保线程安全

当多个线程并发访问共享数据或资源时,Monitor 用于确保线程安全。

通过同步方法或块,您可以防止竞态条件、数据损坏和其他并发问题。

5. 死锁

当两个或多个线程等待对方释放锁时,就会发生死锁,导致程序停滞不前。

适当的设计和仔细使用同步块有助于避免死锁。

DeadlockExample.java

输出

Thread 1: Holding resource1...
Thread 2: Holding resource2...
Thread 1: Waiting for resource2...
Thread 2: Waiting for resource1...

虽然 Monitor 有助于防止竞态条件,但如果使用不当,也可能导致死锁。

Lock 和 Monitor 的主要区别

LockMonitor
简单复杂
线程不等待条件线程等待条件
当需要同步时使用 Lock。当需要复杂同步时使用 Monitor,例如当线程需要等待条件满足时。
Lock 提供更多的控制和灵活性,但需要显式管理。而 Monitor 更易于使用,但提供的精细控制较少。
由 Java 虚拟机 (JVM) 实现。由 JVM 使用 Lock 实现。
用于保护共享资源免受并发访问。用于保护共享资源免受并发访问,并用于协调多个线程的执行。