为什么说Synchronized是可重入锁

举报
赵KK日常技术记录 发表于 2023/07/07 14:07:50 2023/07/07
【摘要】 什么是可重入性在计算机科学领域中,可重入性(Reentrancy)是指一个子程序(函数、方法)可以被多个并发执行的线程同时调用,而不会出现不正确的结果。换句话说,可重入性是指一个子程序可以被多次调用,而每次调用都能正常执行,不会受到之前调用的影响。可重入性是并发编程中的重要概念,因为在多线程环境下,多个线程可能同时访问同一个资源,如果资源不具备可重入性,那么在并发执行的情况下可能会导致数据...

什么是可重入性

在计算机科学领域中,可重入性(Reentrancy)是指一个子程序(函数、方法)可以被多个并发执行的线程同时调用,而不会出现不正确的结果。换句话说,可重入性是指一个子程序可以被多次调用,而每次调用都能正常执行,不会受到之前调用的影响。

可重入性是并发编程中的重要概念,因为在多线程环境下,多个线程可能同时访问同一个资源,如果资源不具备可重入性,那么在并发执行的情况下可能会导致数据不一致、死锁等问题。

为什么说Synchronized是可重入锁

在Java语言中,Synchronized是一种重要的同步机制,它可以用来保护共享资源的访问,避免多个线程同时修改共享资源导致的数据不一致问题。同时,Synchronized也具备可重入性,即同一个线程可以重复获得已经持有的锁,而不会造成死锁或其他错误。

代码演示

下面通过一个简单的代码演示来说明Synchronized的可重入性。

    public synchronized void outer() {
        System.out.println("外层方法开始执行");
        inner();
        System.out.println("外层方法执行结束");
    }

    public synchronized void inner() {
        System.out.println("内层方法执行");
    }

    public static void main(String[] args) {
        ReentrantDemo demo = new ReentrantDemo();
        demo.outer();
    }
}

上述代码中,定义了一个ReentrantDemo类,其中包含了两个同步方法outerinner。在outer方法中,先打印一条消息,然后调用inner方法,最后再打印一条消息。inner方法只是简单地打印一条消息。

main方法中,创建了一个ReentrantDemo对象,并调用了outer方法。

运行上述代码,可以得到以下输出结果:

外层方法开始执行内层方法执行外层方法执行结束```

从输出结果可以看出,`outer`方法和`inner`方法都成功地执行了,而且是按照预期的顺序执行的。

这是因为在Java中,每个对象都有一个与之关联的监视器(monitor),也可以称之为锁。当一个线程进入一个被`synchronized`修饰的方法时,它会尝试获取该方法所属对象的锁。如果该锁没有被其他线程占用,那么当前线程就可以获取到锁,并继续执行方法体中的代码。在方法执行期间,如果该方法再次调用了其他`synchronized`方法,它可以重复获取同一个锁,而不会被阻塞。只有当方法执行结束,线程释放锁之后,其他线程才有机会获取到该锁。

## 可重入性的实现原理

可重入性的实现原理是通过给每个锁分配一个持有线程和一个计数器来实现的。当一个线程第一次获取锁时,计数器会被设置为1,表示该线程持有了一次锁。当同一个线程再次获取同一个锁时,计数器会递增,表示该线程持有了多次锁。只有当计数器归零时,锁才会被释放。

在Java中,Synchronized关键字就是通过这种方式实现可重入性的。每个对象都有一个与之关联的监视器(monitor),当一个线程获取到锁时,会将锁的持有线程设置为当前线程,并将计数器设置为1。当同一个线程再次获取到该锁时,计数器会递增。在方法执行期间,每次递归调用都会增加计数器的值,而在方法执行结束时,计数器会递减。只有当计数器归零时,锁才会被释放,其他线程才有机会获取到该锁。

## Synchronized的可重入性示例

为了更好地理解Synchronized的可重入性,我们可以通过一个示例来演示。

```javapublic class ReentrantDemo {
    public synchronized void outer() {
        System.out.println("外层方法开始执行");
        inner();
        System.out.println("外层方法执行结束");
    }

    public synchronized void inner() {
        System.out.println("内层方法执行");
    }

    public static void main(String[] args) {
        ReentrantDemo demo = new ReentrantDemo();
        demo.outer();
    }
}

在上述示例中,我们定义了一个ReentrantDemo类,其中包含了两个同步方法outer和inner。在outer方法中,我们先打印一条消息,然后调用inner方法,最后再打印一条消息。inner方法只是简单地打印一条消息。

在main方法中,我们创建了一个ReentrantDemo对象,并调用了outer方法。

运行上述代码,可以得到以下输出结果:

外层方法开始执行
内层方法执行
外层方法执行结束```

从输出结果可以看出,outer方法和inner方法都成功地执行了,而且是按照预期的顺序执行的。

这是因为当一个线程进入一个被synchronized修饰的方法时,它会尝试获取该方法所属对象的锁。如果该锁没有被其他线程占用,那么当前线程就可以获取到锁,并继续执行方法体中的代码。在方法执行期间,如果该方法再次调用了其他synchronized方法,它可以重复获取同一个锁,而不会被阻塞。只有当方法执行结束,线程释放锁之后,其他线程才有机会获取到该锁。

Synchronized关键字在Java中被用于实现线程同步,它的可重入性是指当一个线程获得了一个对象的锁后,再次请求该对象锁时,仍然可以获得该锁。换句话说,可重入性允许线程在持有锁的情况下再次进入由同一把锁保护的同步代码块。

可重入性的好处包括:

1. 简化编程:可重入性使得编写递归函数或嵌套调用同步方法更加简单。在递归调用中,线程可以多次获得同一把锁,而不会出现死锁或其他错误。

2. 避免死锁:当一个线程已经持有一个锁时,如果再次请求该锁,由于可重入性,请求会立即成功,不会导致线程阻塞。这样可以避免由于线程间相互等待对方释放锁而导致的死锁。

3. 灵活性:可重入性允许线程在同步代码块内部调用其他需要同步的方法,而不需要重新获取锁。这样可以提高代码的灵活性和可复用性。

总的来说,Synchronized的可重入性使得多线程编程更加简单和灵活,并且可以避免一些潜在的并发问题,提高程序的性能和可靠性。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。