内置锁重入在继承模型中的探讨
在《Java并发编程实战》中讲解内置锁重入时,使用的示例如下:
public class Widget { static {
System.out.println("super static init");
}
public Widget() {
System.out.println("super construct init");
}
pub lic synchronized void doSomething() {
System.out.println("super this is:" + this);
System.out.println("super do something");
}
}
class subWidget extends Widget {
public subWidget() {
System.out.println("sub construct init");
}
static {
System.out.println("sub static init");
}
@Override
public synchronized void doSomething() {
System.out.println("sub this is:" + this);
super.doSomething();
}
}
锁重入是很好理解的,这里的问题在于,引发了更深层次的虚拟机问题。搜索这段代码的理解,网上有很多讨论。首先synchronized修饰的实例方法,相当于synchronized(this),也就是当前对象的实例,如果这个例子成立的话,说明在父类Widget中的synchronized锁的就是子类实例,那么问题来了,众所周期,new一个子类实例时,会先执行父类的构造方法,这相当于实例化父类对象吗?这里调用super.doSomething()为什么锁的是子类实例?这个问题就没多少人能说得清楚了。
js">super static initsub static init
super construct init
sub construct init
sub this is:com.skz.subWidget@1c655221
super this is:com.skz.subWidget@1c655221
super do something
为了验证结果,我们先执行一下代码,打印一下this,发现父类中this确实是指向subWidget对象。结论就是父类并没有实例化,所以以上内置锁代码成立。我们已经知道了结果,可是为什么呢?
要解决这个问题,就需要搞清楚类加载,类实例化,类继承的内存分配问题。关于这些问题的讲解,就只有一本《深入理解Java虚拟机》而已,书中解释了Java对象的内存分配,类加载过程,但是对于继承模型的内存情况以及实例化过程没有详细说明。以此书为据,说一下与问题相关的描述,这里要注意实例化与初始化的区别。
- 类初始化:类加载过程即加载,验证,准备,解析,初始化,初始化是执行类构造器<clinit>()方法的过程,也就是执行类中的所有类成员变量的赋值语句和静态代码块,在初始化子类时,会首先保证父类的初始化。
- 对象创建:类实例化之前,要先执行类加载过程。然后为新生对象分配内存,再执行必要的设置,如这个对象是哪个类的实例,元数据,GC分代年龄等。
通过在网上查找资料,java中,创建子类对象时,父类对象会也被一起创建么? ,这个回答下解释了为什么父类对象不会被创建,调用父类构造方法只是个初始化类实例变量的过程,并不能说明类对象被创建,这个问题的解释涉及到字节码文件结构及指令,这块内容在书中也有讲解,也许是深入理解之后得出的结论。图解Java继承内存分配 这篇文章解释了继承模型下的内存分配问题,super关键字用来引用被屏蔽的成员变量或成员方法,当然还是子类实例了。
至此,我们算是可以理解这个问题的答案了,但是,这些知识内容的源头在哪里呢?这明显没有出版物来解释这些问题,或许英文世界中有更权威的资料与探讨,就等待以后遇到问题再挖掘了。
以上是 内置锁重入在继承模型中的探讨 的全部内容, 来源链接: utcz.com/z/517789.html