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

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

相关推荐
Java技术小馆几秒前
SpringBoot中暗藏的设计模式
java·面试·架构
xiguolangzi1 分钟前
《springBoot3 中使用redis》
java
꧁坚持很酷꧂3 分钟前
配置Ubuntu18.04中的Qt Creator为中文(图文详解)
开发语言·qt·ubuntu
李菠菜8 分钟前
非SpringBoot环境下Jedis集群操作Redis实战指南
java·redis
不当菜虚困21 分钟前
JAVA设计模式——(四)门面模式
java·开发语言·设计模式
ruyingcai66666621 分钟前
用python进行OCR识别
开发语言·python·ocr
m0Java门徒28 分钟前
面向对象编程核心:封装、继承、多态与 static 关键字深度解析
java·运维·开发语言·intellij-idea·idea
liuweidong080231 分钟前
【Pandas】pandas DataFrame radd
开发语言·python·pandas
无心水1 小时前
【Java面试笔记:基础】8.对比Vector、ArrayList、LinkedList有何区别?
java·笔记·面试·vector·arraylist·linkedlist
农民也会写代码1 小时前
dedecms织梦arclist标签noflag属性过滤多个参数
开发语言·数据库·sql·php·dedecms