Java进阶篇--可重入锁 & 不可重入锁

目录

可重入锁(ReentrantLock):

不可重入锁(NonReentrantLock):

总结

代码示例


当涉及到线程同步和互斥访问共享资源时,可重入锁和不可重入锁是两种常见的锁机制。

可重入锁(ReentrantLock):

  • 可重入锁是一种支持重进入的锁机制。重进入是指一个线程在持有锁的情况下,可以再次获取相同的锁而不会被阻塞。
  • 可重入锁实现了Lock接口,提供了比内置锁(synchronized关键字)更多的灵活性和功能。
  • 可重入锁允许一个线程反复获得该锁,避免了死锁的发生,同时也提高了代码的简洁性和可读性。
  • 可重入锁支持公平性设置,使得等待时间最长的线程优先获取锁。

不可重入锁(NonReentrantLock):

  • 不可重入锁是一种不支持重进入的锁机制。也就是说,当一个线程获得了不可重入锁之后,如果再次尝试获取锁,就会被阻塞,直到当前持有锁的线程释放锁。
  • 不可重入锁在Java中没有内置的实现,需要通过自定义实现或基于AQS(AbstractQueuedSynchronizer)等基础类来构建。
  • 不可重入锁可能会导致死锁问题,因为如果一个线程在持有锁的情况下又尝试获取同一个锁,就会导致自己无限等待。

总结

可重入锁允许同一线程多次获得锁,而不可重入锁则不支持同一个线程多次获得锁。在大多数情况下,可重入锁是更常用和推荐的选择,因为它提供了更多的功能、灵活性和安全性,同时避免了死锁问题。但在某些特殊情况下,不可重入锁也可能有其应用场景,例如需要强制确保某段代码只能被一个线程执行。

代码示例

以下是一个将可重入锁(ReentrantLock)和不可重入锁(NonReentrantLock)结合在一起的代码示例,

java 复制代码
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() 方法实现线程同步。

请注意,混合使用可重入锁和不可重入锁可能需要谨慎处理,以避免死锁和其它线程同步问题。

相关推荐
lili-felicity1 分钟前
CANN多模型并发部署与资源隔离
开发语言·人工智能
小龙报6 分钟前
【51单片机】深度解析 51 串口 UART:原理、配置、收发实现与工程化应用全总结
c语言·开发语言·c++·stm32·单片机·嵌入式硬件·51单片机
qq_5324535314 分钟前
使用 Three.js 构建沉浸式全景图AR
开发语言·javascript·ar
Coder_Boy_15 分钟前
基于SpringAI的在线考试系统-整体架构优化设计方案
java·数据库·人工智能·spring boot·架构·ddd
浅念-16 分钟前
C语言——动态内存管理
c语言·开发语言·c++·笔记·学习
草履虫建模6 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq8 小时前
分布式系统安全通信
开发语言·c++·算法
qq_297574679 小时前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
老毛肚9 小时前
MyBatis插件原理及Spring集成
java·spring·mybatis
学嵌入式的小杨同学9 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux