java.util.concurrent.locks.Locks和ynchronized

Lock接口提供了比synchronized更灵活的锁定操作,支持多个Condition对象及多种属性。它允许以不同的作用域获取和释放锁,实现复杂的技术如hand-over-hand锁定。
public interface LockLock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。

synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。

虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。

随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:

Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。

Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。

注意,Lock 实例只是普通的对象,其本身可以在 synchronized 语句中作为目标使用。获取 Lock 实例的监视器锁与调用该实例的任何 lock() 方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用 Lock 实例。

除非另有说明,否则为任何参数传递 null 值都将导致抛出 NullPointerException。
`java.util.concurrent.locks.ReentrantLock` 是 Java 并发编程中一个重要的工具,属于 `java.util.concurrent.locks` 包,提供了比内置 `synchronized` 关键字更为灵活的锁机制,用于多线程环境下的同步控制[^1]。 ### 特点 - **可重入性**:同一个线程可以多次获取同一把锁,而不会出现死锁的情况。在获取锁时,锁的持有计数会增加;释放锁时,持有计数会减少,直到计数为 0 时,锁才被完全释放[^3]。 - **公平性选择**:支持公平锁非公平锁。公平锁会按照线程请求锁的顺序依次获取锁;非公平锁则允许线程在锁被释放时直接尝试获取锁,而不考虑等待顺序。默认情况下,`ReentrantLock` 是非公平锁。 - **可中断性**:线程在等待获取锁的过程中,可以被中断,避免无限期等待。 - **条件变量支持**:可以通过 `newCondition()` 方法创建多个条件变量,实现更精细的线程间协作。 ### 使用方法 ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private final ReentrantLock lock = new ReentrantLock(); public void performTask() { lock.lock(); try { // 执行需要同步的操作 System.out.println("Task is being executed."); } finally { lock.unlock(); } } public static void main(String[] args) { ReentrantLockExample example = new ReentrantLockExample(); example.performTask(); } } ``` 在上述代码中,`lock.lock()` 方法用于获取锁,`lock.unlock()` 方法用于释放锁。为了确保锁最终能被释放,通常将释放锁的操作放在 `finally` 块中。 ### 原理 `ReentrantLock` 是基于 AQS(AbstractQueuedSynchronizer)实现的。AQS 使用一个整型的 `volatile` 变量(命名为 `state`)来维护同步状态,这是 `ReentrantLock` 内存语义实现的关键。在 `ReentrantLock` 中,不管是公平锁还是非公平锁,当锁的状态 `c` 为 0 时,表示锁未被持有,尝试通过 `compareAndSetState` 方法来获取锁。如果当前线程已经持有了锁,再次获取锁时,会将锁的状态值 `c` 增加,体现了可重入性。当释放锁时,会将状态值 `c` 减少,直到为 0 时表示锁被完全释放[^4]。 ### 应用场景 `ReentrantLock` 提供了一种灵活且功能强大的线程同步机制,尤其适用于复杂的并发场景。相比于 `synchronized`,`ReentrantLock` 允许更细粒度的控制,并支持公平锁、可中断锁可重入锁等高级特性。在业务应用中,`ReentrantLock` 可以确保高并发情况下共享资源的正确性,适用于电商、库存管理等系统[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值