关于内置锁的可重入性

本文深入解析了Java并发编程实践中的synchronized内置锁机制,特别是可重入实例,通过LoggingWidget类展示了当子类调用父类方法时锁对象的归属,并解释了死锁现象的原理。

 

《java并发编程实践》一书中,关于synchronized内置锁的可重入的例子如下:

------------------------------------------------------------------------------------------------------

public class Widget {

    public synchronized void doSomething() {

        ...

    }

}

 

public class LoggingWidget extends Widget {

    public synchronized void doSomething() {

        System.out.println(toString() + ": calling doSomething");

        super.doSomething();//若内置锁是不可重入的,则发生死锁

    }

}

-------------------------------------------------------------------------------------------------------

小弟在此次有两点疑惑:

1、LoggingWidget 的对象调用doSomething方法时,锁对象为LoggingWidget对象

     super.doSomething()调用是锁对象是谁?LoggingWidget对象 还是 Widget 的Class对象?

 

     运行程序,查看thread dump发现:调用super.doSomething()时锁对象依然是LoggingWidget对象

 

     "线程#1" prio=6 tid=0x0bd60400 nid=0x16f8 waiting on condition [0x0bf8f000..0x0bf8fd68]

   java.lang.Thread.State: TIMED_WAITING (sleeping)

at java.lang.Thread.sleep(Native Method)

at Widget.doSomething(Widget.java:4)

- locked <0x03fbc150> (a LoggingWidget)

at LoggingWidget.doSomething(LoggingWidget.java:5)

- locked <0x03fbc150> (a LoggingWidget)

at LoggingWidget$1.run(LoggingWidget.java:15)

 

   Locked ownable synchronizers:

- None

 

2、在网上搜索发现,大伙都如是说:

 


请大家讨论一下,在子类调用父类方法时,是否同时获取父类的锁(父类的class对象?)
<think>嗯,用户现在想了解Java中synchronized锁的可重入及其原理。根据之前的对话历史,用户已经接触过Seata协议的相关内容,但现在转向了Java并发的问题。需要确保回答准确且符合用户提供的引用内容。 首先,用户的问题很明确:synchronized是否可重入,以及原理是什么。引用中的资料提到synchronized是可重入的,并且解释了可重入锁的实现原理,比如通过记录持有线程和持有数量。比如引用[3]和引用[5]都提到这一点。 我需要先确认用户可能已经知道什么。用户可能已经了解synchronized的基本用法,比如修饰代码块和方法,但可能对可重入的具体机制不太清楚。用户提供的引用中有示例代码,比如引用[2]中的ReentrantLockExample,展示了方法A和方法B都使用同一个锁的情况,说明同一线程可以多次获取锁,这就是可重入的体现。 接下来,需要组织回答的结构。根据用户之前的回答风格,分点回答会比较清晰。例如,先回答是否可重入,再解释原理,接着与ReentrantLock的对比,最后总结应用场景。同时要引用用户提供的引用资料来支持观点。 需要注意用户提供的引用中有一些关于Reentrant Lock的对比,比如引用[4]提到synchronized是隐式获取释放锁,而ReentrantLock需要显式调用。但在回答synchronized的可重入时,可能不需要深入对比,但可以简要提及,以帮助理解不同锁的实现差异。 另外,用户提供的引用[5]详细说明了synchronized的实现原理,包括锁对象头中的计数器和持有线程信息。这部分需要转化为更易懂的语言,避免过于技术化的术语,但保持准确。 可能存在的疑问点:用户是否了解对象头、Monitor等底层概念?需要适当解释,但不要过于深入,以免混淆。例如,可以提到JVM通过对象头中的计数器来跟踪锁的重入次数,而不必展开对象头的具体结构。 还要检查是否有遗漏的信息。例如,synchronized的可重入是否有限制?根据资料,同一线程可以多次获取同一锁,没有限制次数,但需要正确释放,即每次进入同步块计数器加一,退出时减一,直到为零才释放锁。这点需要明确说明。 最后,生成相关问题部分,需要考虑用户可能进一步的问题,比如与ReentrantLock的区别,或者实际应用中的注意事项。根据引用中的内容,可以提出关于实现原理对比、应用场景选择等问题,帮助用户深入理解。</think>### Java中synchronized锁的可重入及原理分析 #### 一、synchronized是否可重入? **是的,synchronized锁是可重入的**。 在Java中,同一线程可以多次获取同一个对象锁,而不会因锁已被自身持有而阻塞。例如以下场景均可正常执行: 1. 同一线程递归调用`synchronized`方法。 2. 同一线程在`synchronized`代码块内调用另一个`synchronized`方法(锁对象相同)。 3. 子类通过`synchronized`方法调用父类的`synchronized`方法(锁对象为实例本身)[^3]。 **示例**(基于引用[2]的代码扩展): ```java public class ReentrantDemo { public synchronized void methodA() { methodB(); // 同一线程可重入锁 } public synchronized void methodB() { System.out.println("Reentrant call"); } } ``` 上述代码中,线程调用`methodA`时会自动获取实例锁,并在调用`methodB`时再次获取同一锁而不会阻塞。 --- #### 二、synchronized可重入的实现原理 ##### 1. **锁的持有者与计数器** - **对象头标记**:每个Java对象都与一个监视器(Monitor)关联,对象头中存储了锁状态、持有线程和重入计数器[^5]。 - **计数器机制**: - 当线程首次获取锁时,计数器置为1。 - 每次重入(同一线程再次获取锁),计数器**递增**。 - 退出同步代码块时,计数器**递减**,直至归零时释放锁[^5]。 ##### 2. **源码级逻辑** ```java // 伪代码示意 if (当前线程 == 锁持有线程) { 计数器++; } else { 竞争锁或加入等待队列; } ``` ##### 3. **关键设计特点** - **粒度控制**:锁的获取以**线程**为粒度,而非方法调用(即“per-thread”而非“per-invocation”)[^3]。 - **避免死锁**:可重入避免了线程因重复请求自身已持有的锁而导致的死锁。 --- #### 三、与ReentrantLock的对比 虽然两者均支持可重入,但实现方式不同: | 特 | synchronized | ReentrantLock | |--------------------|----------------------------------|------------------------------| | **锁获取/释放** | 自动(进入/退出代码块时触发)[^4] | 手动(`lock()`/`unlock()`)[^4] | | **实现机制** | JVM内置锁,通过对象头实现 | 基于AQS(AbstractQueuedSynchronizer) | | **灵活** | 有限 | 支持公平锁、条件变量等 | --- #### 四、应用场景与注意事项 1. **适用场景**: - 方法递归调用。 - 多层同步代码块的嵌套执行(如调用链中的多个同步方法)。 2. **风险提示**: - **锁泄漏**:若重入次数未正确释放(如异常跳过`monitorexit`),可能导致锁无法释放。 - **能影响**:过深的锁重入可能增加竞争概率,需合理设计同步范围。 --- ### 相关问题 1. **synchronized的可重入与ReentrantLock的实现机制有何本质区别?** 2. **若synchronized的计数器溢出会发生什么?Java如何避免这种情况?** 3. **在分布式系统中,synchronized的可重入是否仍然有效?为什么?** 4. **如何通过JVM工具(如jstack)观察synchronized锁的重入次数?**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值