目录
当涉及到线程同步和互斥访问共享资源时,可重入锁和不可重入锁是两种常见的锁机制。
可重入锁允许同一线程多次获得锁,而不可重入锁则不支持同一个线程多次获得锁。在大多数情况下,可重入锁是更常用和推荐的选择,因为它提供了更多的功能、灵活性和安全性,同时避免了死锁问题。但在某些特殊情况下,不可重入锁也可能有其应用场景,例如需要强制确保某段代码只能被一个线程执行。
以下是一个将可重入锁(ReentrantLock)和不可重入锁(NonReentrantLock)结合在一起的代码示例,
- import java.util.concurrent.locks.ReentrantLock;
-
- public class main {
- private static ReentrantLock reentrantLock = new ReentrantLock(); // 创建可重入锁对象
- private static NonReentrantLock nonReentrantLock = new NonReentrantLock(); // 创建不可重入锁对象
-
- public static void main(String[] args) {
- Thread thread1 = new Thread(new ReentrantTask());
- Thread thread2 = new Thread(new NonReentrantTask());
-
- thread1.start();
- thread2.start();
- }
-
- static class ReentrantTask implements Runnable {
- @Override
- public void run() {
- reentrantLock.lock(); // 获取可重入锁
-
- try {
- System.out.println(Thread.currentThread().getName() + "进入可重入锁临界区");
- criticalSectionWithReentrantLock();
- System.out.println(Thread.currentThread().getName() + "离开可重入锁临界区");
- } finally {
- reentrantLock.unlock(); // 释放可重入锁
- }
- }
-
- private void criticalSectionWithReentrantLock() {
- reentrantLock.lock(); // 可重入锁允许同一线程多次获得锁
-
- try {
- // 在可重入锁临界区域执行需要同步的操作
- System.out.println(Thread.currentThread().getName() + "正在执行可重入锁临界区操作");
- } finally {
- reentrantLock.unlock(); // 释放可重入锁
- }
- }
- }
-
- static class NonReentrantTask implements Runnable {
- @Override
- public void run() {
- nonReentrantLock.lock(); // 获取不可重入锁
-
- try {
- System.out.println(Thread.currentThread().getName() + "进入不可重入锁临界区");
- criticalSectionWithNonReentrantLock();
- System.out.println(Thread.currentThread().getName() + "离开不可重入锁临界区");
- } finally {
- nonReentrantLock.unlock(); // 释放不可重入锁
- }
- }
-
- private void criticalSectionWithNonReentrantLock() {
- nonReentrantLock.lock(); // 不可重入锁不允许同一线程多次获得锁
-
- try {
- // 在不可重入锁临界区域执行需要同步的操作
- System.out.println(Thread.currentThread().getName() + "正在执行不可重入锁临界区操作");
- } finally {
- nonReentrantLock.unlock(); // 释放不可重入锁
- }
- }
- }
-
- static class NonReentrantLock {
- private boolean isLocked = false;
-
- public synchronized void lock() {
- while (isLocked) {
- try {
- wait(); // 等待直到当前线程获取锁
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
-
- isLocked = true;
- }
-
- public synchronized void unlock() {
- isLocked = false;
- notify(); // 唤醒等待的线程
- }
- }
- }
在这个示例中,我们创建了一个可重入锁对象 reentrantLock 和一个不可重入锁对象 nonReentrantLock ,并在 ReentrantTask 和 NonReentrantTask 类中分别使用这两种类型的锁来实现线程同步。
ReentrantTask 类使用可重入锁,在 run() 方法中获取可重入锁并进入临界区域执行操作,而且可以在临界区域内再次获得相同的锁。这展示了可重入锁的特性。
NonReentrantTask 类使用不可重入锁,在 run() 方法中获取不可重入锁并进入临界区域执行操作,但是如果尝试再次获取相同的锁,将被阻塞。这展示了不可重入锁的特性。
注意,不可重入锁 NonReentrantLock 是通过自定义类实现的。它使用一个布尔变量 isLocked 来表示当前锁是否被占用,并在 lock() 和 unlock() 方法中使用 synchronized 关键字和 wait()、notify() 方法实现线程同步。
请注意,混合使用可重入锁和不可重入锁可能需要谨慎处理,以避免死锁和其它线程同步问题。