ReenTrantLock可重入锁(和synchronized的区别)

本文对比分析了ReentrantLock与synchronized关键字的区别,包括可重入性、锁的实现方式、性能表现及功能特性等。重点介绍了ReentrantLock提供的公平锁、Condition条件类以及中断等待锁的线程等独特功能。

来源:https://blog.youkuaiyun.com/qq838642798/article/details/65441415

ReenTrantLock可重入锁(和synchronized的区别)总结

可重入性:

从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大。两者都是同一个线程没进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。

锁的实现:

Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的,有什么区别,说白了就类似于操作系统来控制实现和用户自己敲代码实现的区别。前者的实现是比较难见到的,后者有直接的源码可供阅读。

性能的区别:

在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

功能区别:

便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。

锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized

ReenTrantLock独有的能力:

  1. ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。

  2. ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。

  3. ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。

ReenTrantLock实现的原理:

在网上看到相关的源码分析,本来这块应该是本文的核心,但是感觉比较复杂就不一一详解了,简单来说,ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。

什么情况下使用ReenTrantLock:

答案是,如果你需要实现ReenTrantLock的三个独有功能时。

### synchronized ReentrantLock 是否为可重入及其特性比较 #### 1. 可重入的概念 可重入是指一个线程已经获取到的情况下,能够再次获取同一把而不发生死的情况。这种的设计使得线程可以在不同的嵌套层次上重复进入已持有的区域[^5]。 --- #### 2. synchronized可重入 `synchronized` 是 Java 原生的关键字实现的机制,具有天然的可重入性。这意味着如果一个线程进入了某个由 `synchronized` 守护的方法或代码块后,它可以继续访问其他由相同守护的方法或代码块,而不会因重复加而导致死[^3]。 ```java class SynchronizedExample { private int count; public synchronized void increment() { this.count++; // 此处调用了另一个同步方法 decrement() decrement(); } public synchronized void decrement() { this.count--; } } ``` 在上面的例子中,`increment()` 方法内部调用了同样被 `synchronized` 关键字保护的 `decrement()` 方法。由于 `synchronized` 的可重入性,当前线程可以顺利执行这两个方法,无需担心死问题[^1]。 --- #### 3. ReentrantLock可重入 `ReentrantLock` 是 Java 提供的一个显式类,位于 `java.util.concurrent.locks` 包中。它同样是可重入,允许同一个线程多次获取相同的实例,并且每次获取都需要匹配一次解操作[^5]。 ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private final Lock lock = new ReentrantLock(); private int count; public void increment() { lock.lock(); // 获取 try { this.count++; decrement(); // 调用另一个需要的方法 } finally { lock.unlock(); // 释放 } } public void decrement() { lock.lock(); // 再次获取 try { this.count--; } finally { lock.unlock(); // 再次释放 } } } ``` 在这个例子中,`increment()` 方法 `decrement()` 方法都使用了 `ReentrantLock` 进行同步控制。即使 `increment()` 方法内部调用了 `decrement()` 方法,也不会引发死,因为 `ReentrantLock` 支持可重入性[^2]。 --- #### 4. synchronized ReentrantLock 的特性对比 | 特性 | synchronized | ReentrantLock | |--------------------------|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | **底层实现** | JVM 层面的原生关键字 | API 层面的显式 | | **加方式** | 隐式加,无须手动干预 | 显式加,需通过 `lock.lock()` `lock.unlock()` 控制 | | **适用范围** | 只能用于修饰方法或代码块 | 可以单独作用于代码块,也可以绑定多个条件 | | **功能扩展** | 不提供额外功能 | 提供更多高级功能,如等待可中断、公平支持、绑定多个条件 | | **性能表现** | 在简单场景下通常优于 `ReentrantLock` | 更适合复杂场景,尤其是需要高级特性的场合 | --- #### 5. 使用场景分析 ##### (1)synchronized 的典型使用场景 - 场景较为简单的同步需求。 - 开发者希望减少代码复杂度,利用 JVM 自动管理的行为。 - 性能要求较高的短时间同步操作,尤其是在 JDK 1.6 以后优化后的轻量级偏向技术支持下[^4]。 ##### (2)ReentrantLock 的典型使用场景 - 需要更精细的控制,例如等待超时、响应中断等功能。 - 处理复杂的多线程协作逻辑,特别是涉及多个条件变量时。 - 当需要实现公平或者非公平切换时。 ```java // 使用 ReentrantLock 实现带超时的尝试 Lock lock = new ReentrantLock(); if (lock.tryLock(10, TimeUnit.SECONDS)) { try { // 成功获取后执行业务逻辑 } finally { lock.unlock(); } } else { System.out.println("未能在指定时间内获取"); } ``` --- #### 6. 总结 `synchronized` `ReentrantLock` 都是可重入,但在具体应用场景上有显著的区别。前者更适合简单场景下的快速开发,后者则提供了更高的灵活性更强的功能支持,适用于复杂并发环境下的精细化控制。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值