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

目录

可重入锁(ReentrantLock):

不可重入锁(NonReentrantLock):

总结

代码示例


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

可重入锁(ReentrantLock):

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

不可重入锁(NonReentrantLock):

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

总结

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

代码示例

以下是一个将可重入锁(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() 方法实现线程同步。

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

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,请问您已经从事过Java开发工作吗? (注:由于我是一个语言模型AI,对于涉及工作经验和实际情况的问题,我只能给出一般性的回答,不能根据您的具体情况进行针对性的建议,希望您理解。) 无论您是否已经有了Java开发经验,制定一份职业生涯规划是非常重要的。下面,我将根据一般化的情况给出关于如何制定Java开发职业生涯规划的建议,希望能帮助到您。 首先,您需要了解Java开发所需的技能和技术趋势。 Java技术更新比较迅速,您需要通过学习和实践来不断获得新知识。以下是几个方面的建议: 一、掌握Java基础。Java语言的基础非常重要,您需要掌握Java的基本语法、面向对象编程、数据结构和算法等。 二、学习Java框架和工具。目前比较流行的Java框架有Spring、Hibernate、MyBatis等,您需要掌握这些框架的使用。此外,使用工具来提高开发效率是非常重要的,如Eclipse、IntelliJ IDEA、Maven、Git等。 三、了解云计算和大数据技术。云计算和大数据技术已经成为Java开发不可或缺的技能。您需要了解云计算的基本概念和常用的云计算平台,如AWS、Azure、Google Cloud等。针对大数据技术,您需要了解Hadoop、Spark、Hive等技术的基本概念和使用方法。 四、跟紧时代的步伐。技术更新迭代很快,您需要密切关注最新的技术趋势和发展方向,如云原生、人工智能和机器学习等。 接下来,您需要为您的Java开发职业生涯设定一些目标。具体而言,您可参考以下步骤: 一、确定您职业发展的方向。Java开发的职业方向很广,您可以选择做桌面应用开发、web开发、移动应用开发、游戏开发、后台开发、大数据开发等等。坚持几年专注于一项领域,深耕细作,往往能取得更好的发展前景。 二、设定职业生涯目标。考虑您的职业生涯规划,您要设定一些具体的职业目标,如从初级Java开发工程师到高级工程师、从开发工程师到架构师等,并且需要有具体的时间规划和进阶路线。 三、寻求职业发展机会。您需要关注各种招聘网站、社交平台等渠道,了解当前市场需求,掌握有关Java开发工程师的岗位信息、薪资待遇和职业发展方向等。 最后,您要持续学习和实践,不断提高自我水平。这是职业生涯规划的关键所在。学习不仅是学习新的技术知识,也是在实践中发现问题、解决问题和积累经验的过程。因此,您需要参与到项目中去,亲自实践,在实践中掌握技能和经验,不断提高职业水平。 以上是我关于如何制定Java开发职业生涯规划的建议,希望对您的职业发展有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员老李头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值