Java中的可重入锁(ReentrantLock)技术详解

Java中的可重入锁(ReentrantLock)技术详解

在Java并发编程中,锁是保证数据在多线程环境下一致性和安全性的重要机制。Java标准库提供了多种锁的实现,其中ReentrantLock是可重入锁的一个典型实现,它属于java.util.concurrent.locks包。相比于内置的synchronized关键字,ReentrantLock提供了更灵活和强大的功能。

1. 可重入锁的概念

可重入锁(ReentrantLock)允许同一线程多次获取同一把锁,而不会造成死锁。这种特性使得锁在同一线程内可以被递归使用,从而避免了在递归调用时可能出现的死锁问题。

2. ReentrantLock的基本使用

使用ReentrantLock的基本步骤如下:

  1. 创建一个ReentrantLock对象。
  2. 在需要加锁的代码块前调用lock()方法获取锁。
  3. 在需要释放锁的代码块后调用unlock()方法释放锁。

示例代码:

 

java复制代码

import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void someMethod() {
lock.lock(); // 获取锁
try {
// 临界区,同一时间只有一个线程能执行这里的代码
// ...
} finally {
lock.unlock(); // 释放锁
}
}
// 递归调用示例
public void recursiveMethod() {
lock.lock();
try {
// ...
recursiveMethod(); // 递归调用自身,仍然可以获取锁
// ...
} finally {
lock.unlock();
}
}
}
3. ReentrantLock的特性
  • 可重入性:同一个线程可以多次获取同一把锁,而不会被阻塞。
  • 公平锁与非公平锁ReentrantLock可以构造为公平锁或非公平锁。公平锁会按照线程请求锁的顺序来分配锁,而非公平锁则可能允许插队,即新请求的线程可能会立即获取锁,而等待时间较长的线程可能会继续等待。默认情况下,ReentrantLock是非公平锁。
  • 中断响应:与synchronized不同,ReentrantLock支持对等待锁的线程进行中断。
  • 尝试锁ReentrantLock提供了tryLock()方法,该方法会尝试获取锁,如果锁当前可用则获取锁并立即返回true,否则立即返回false
  • 定时锁ReentrantLock还提供了tryLock(long timeout, TimeUnit unit)方法,该方法会尝试获取锁,但如果在给定的等待时间内仍然没有获取到锁,则返回false
4. ReentrantLock与synchronized的比较
  • synchronized是Java内置的关键字,使用方便但功能有限;而ReentrantLock是Java标准库中的一个类,提供了更多的功能。
  • ReentrantLock支持公平锁和非公平锁,而synchronized只有非公平锁。
  • ReentrantLock支持对等待锁的线程进行中断,而synchronized不支持。
  • ReentrantLock提供了更灵活的锁控制,如尝试锁和定时锁,而synchronized不支持这些功能。
5. 总结

ReentrantLock作为Java中的一个可重入锁实现,提供了比synchronized更强大和灵活的功能。在需要更精细控制锁的行为时,使用ReentrantLock是一个很好的选择。然而,由于其使用相对复杂,需要确保在finally块中释放锁,以避免潜在的死锁问题。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
重入锁(ReentrantLock)是一种独占锁,也就是说同一时间只能有一个线程持有该锁。与 synchronized 关键字不同的是,重入锁可以支持公平锁和非公平锁两种模式,而 synchronized 关键字只支持非公平锁。 重入锁的实现原理是基于 AQS(AbstractQueuedSynchronizer)框架,利用了 CAS(Compare And Swap)操作和 volatile 关键字。 重入锁的核心思想是“可重入性”,也就是说如果当前线程已经持有了该锁,那么它可以重复地获取该锁而不会被阻塞。在重入锁内部,使用了一个计数器来记录当前线程持有该锁的次数。每当该线程获取一次锁时,计数器就加 1,释放一次锁时,计数器就减 1,只有当计数器为 0 时,其他线程才有机会获取该锁。 重入锁的基本使用方法如下: ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockTest { private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { new Thread(() -> { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " get lock"); Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + " release lock"); } }, "Thread-1").start(); new Thread(() -> { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " get lock"); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + " release lock"); } }, "Thread-2").start(); } } ``` 在上面的示例代码,我们创建了两个线程,分别尝试获取重入锁。由于重入锁支持可重入性,因此第二个线程可以成功地获取到该锁,而不会被阻塞。当第一个线程释放锁后,第二个线程才会获取到锁并执行相应的操作。 需要注意的是,使用重入锁时一定要记得在 finally 块释放锁,否则可能会导致死锁的问题。同时,在获取锁时也可以设置超时时间,避免由于获取锁失败而导致的线程阻塞问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值