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() 方法实现线程同步。

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

相关推荐
程序员 小柴6 分钟前
RabbitMQ死信队列
java·rabbitmq·java-rabbitmq
小赖同学吖7 分钟前
Java 中的继承与多态:面向对象编程的核心特性
java·开发语言
萧鼎13 分钟前
Python WebSockets 库详解:从基础到实战
开发语言·python
长潇若雪16 分钟前
《STL 六大组件之容器篇:简单了解 list》
开发语言·c++·经验分享·list·类和对象
Seven9730 分钟前
【Guava】集合工具Collections2
java
MaCa .BaKa31 分钟前
25-智慧旅游系统(协同算法)三端
java·javascript·vue.js·spring boot·tomcat·maven·旅游
西元.36 分钟前
线程等待与唤醒的几种方法与注意事项
java·开发语言
栗筝i39 分钟前
Spring 核心技术解析【纯干货版】- XVI:Spring 网络模块 Spring-WebMvc 模块精讲
java·网络·spring
独好紫罗兰44 分钟前
洛谷题单2-P5717 【深基3.习8】三角形分类-python-流程图重构
开发语言·python·算法
落榜程序员1 小时前
Java基础-25-继承-方法重写-子类构造器的特点-构造器this的调用
java·开发语言