- 浏览: 955257 次
- 性别:
- 来自: 魔都
文章分类
- 全部博客 (745)
- MultiThread (19)
- My Plan (118)
- JavaBasic (61)
- MyInterview (104)
- InternetTechnique (5)
- ProjectConclusion (1)
- Maven (5)
- MogoDb (5)
- Hadoop (11)
- Memcached (6)
- TechniqueCollect (1)
- Ibaits (1)
- Android (34)
- ItLife (40)
- Tree (2)
- ProjectArchitect (7)
- Open Source (3)
- liunx (5)
- socket (8)
- Spring (27)
- DesginPattern (35)
- WebBasic (13)
- English (13)
- structs (1)
- structs2 (2)
- Oracle (17)
- Hibernate (2)
- JavaScript (4)
- Jdbc (1)
- Jvm (15)
- Ibatis (1)
- DataStructures (13)
- Https/Socket/Tcp/Ip (3)
- Linux (4)
- Webservice (7)
- Io (2)
- Svn (1)
- Css (1)
- Ajax (1)
- ExtJs (1)
- UML (2)
- DataBase (6)
- BankTechnique (3)
- SpringMvc (3)
- Nio (3)
- Load Balancing/Cluster (3)
- Tools (1)
- javaPerformanceOptimization (8)
- Lucene(SEO) (1)
- My Think (80)
- NodeJs (1)
- Quartz (1)
- Distributed-java (1)
- MySql (7)
- Project (4)
- junit (4)
- framework (1)
- enCache (1)
- git (2)
- SCJP (1)
- sd (1)
最新评论
-
lkjxshi:
你都这水平了还考这个证干嘛
SCJP 认证考试指南 -
钟逸华:
问的真多
百度java开发面试题(转) -
zuimeitulip:
觉得我就是这样的,从小阅读量就很少,导致现在的读的速度非常慢, ...
让读书成为一种习惯 -
DDT_123456:
我觉得你是不符合要求。问你hashmap的那个问题,你那样回答 ...
阿里面试2(转) -
jingjing0907:
刚刚写了很多读过此博客的感受,竟然没有发上去,以为我注册账号还 ...
让读书成为一种习惯
面先说一下环境,比如现在有两个类,A和B,两个类都是单例类,这个时候如果A有个B的实例变量,B有个A的实例变量,会发生什么情况呢?开始我以为会出现栈溢出。但是让我迷惑的是,居然没问题。只是其中一个类的 实例变量会是NULL。下面看代码。
Java代码
public class A {
private static A a = new A();
private B b = B.getInstance();
private A() {
}
public static A getInstance() {
System.out.println("A被调用");
return a;
}
public void test() {
System.out.println(b);
}
}
public class A {
private static A a = new A();
private B b = B.getInstance();
private A() {
}
public static A getInstance() {
System.out.println("A被调用");
return a;
}
public void test() {
System.out.println(b);
}
}
Java代码
public class B {
private static B b = new B();
private A a = A.getInstance();
private B() {
}
public static B getInstance() {
System.out.println("B被调用");
return b;
}
public void test() {
System.out.println(a);
}
}
public class B {
private static B b = new B();
private A a = A.getInstance();
private B() {
}
public static B getInstance() {
System.out.println("B被调用");
return b;
}
public void test() {
System.out.println(a);
}
}
Java代码
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
B b = B.getInstance();
b.test();
System.out.println("==========");
A a = A.getInstance();
a.test();
//A a = A.getInstance();
//a.test();
//System.out.println("==========");
//B b = B.getInstance();
//b.test();
//System.out.println("==========");
}
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
B b = B.getInstance();
b.test();
System.out.println("==========");
A a = A.getInstance();
a.test();
//A a = A.getInstance();
//a.test();
//System.out.println("==========");
//B b = B.getInstance();
//b.test();
//System.out.println("==========");
}
}
得到的结果是:
B被调用
A被调用
B被调用
A@35ce36
==========
A被调用
null
我原本在第一个getInstance的时候会出现 递归调用初始化 而
死锁的问题。但是没有,你知道JVM对于 构造方法的初始化是如何实现的。大家说说。
引用 收藏
IcyFenix 2011-04-09
大致的执行过程如下,本来想直接贴Javap的字节码了事的,不过整理了一下后发现贴了估计也看不清楚,所以过程还是用中文大致写了一些:
类Test的main()方法的B.getInstance()生成的invokestatic指令触发了类B的初始化
执行类B的<clinit>方法的过程中,显式调用了B自己的<init>方法(static b = new B())
B的<init>方法中,调用A.getInstance()生成的invokestatic指令触发了A的初始化(private A a = A.getInstance())
执行A的<clinit>方法的过程中调用了A自己的<init>方法(static a = new A())
类A的<init>方法中需要调用B.getInstance(),但是虚拟机中一个类(<class,classloader>为一个类)只会初始化一次,因此不会再触发B的初始化,既不会再执行B.<clinit>方法。
那由a.<init>触发的B.getInstance()被执行,输出第一行“B被调用”,B.getInstance()方法结束。虽然这时候B的初始化阶段尚未结束,但是解析阶段已经完成,所以getInstance()方法可以被正确执行,但这时候静态字段static B b仍然为null(注意,b.<init>方法还没完呢),所以这个B.getInstance()方法返回值为null,所以A.b为null。
A.<clinit>方法结束,第3步的invokestatic指令正式执行,即A.getInstance()被执行,输出第二行“A被调用”,返回A的实例,这时候B.a不为null了。
B.<clinit>方法结束,第1步的invokestatic指令正式执行,即B.getInstance()被执行,输出第三行“B被调用”
B.test()方法被执行,输出B.a的toString()方法结果,即第四行“A@35ce36”。
A.getInstance()方法被执行,输出第五行“A被调用”。
A.test()方法被执行,输出null,即A.b的值。
这样写应该比较好懂了吧?
引用 收藏
Anddy 2011-04-09
如果你的想法跟我一样,看看我的分析流程,就一下子明白。
B--> B.getInstance() --- new B()
| |
| |
| |
new A() < ---- A.getInstance()
在new A() 中调用 B.getInstance(),return b ; 但是 b是静态成员,在B类加载的时候已经记录在静态存储区 【只是值为null】。 不会在去调用B.getInstance() 方法, 所以这个死锁不存在。
引用 收藏
xgj1988 2011-04-10
IcyFenix 写道
大致的执行过程如下,本来想直接贴Javap的字节码了事的,不过整理了一下后发现贴了估计也看不清楚,所以过程还是用中文大致写了一些:
类Test的main()方法的B.getInstance()生成的invokestatic指令触发了类B的初始化
执行类B的<clinit>方法的过程中,显式调用了B自己的<init>方法(static b = new B())
B的<init>方法中,调用A.getInstance()生成的invokestatic指令触发了A的初始化(private A a = A.getInstance())
执行A的<clinit>方法的过程中调用了A自己的<init>方法(static a = new A())
类A的<init>方法中需要调用B.getInstance(),但是虚拟机中一个类(<class,classloader>为一个类)只会初始化一次,因此不会再触发B的初始化,既不会再执行B.<clinit>方法。
那由a.<init>触发的B.getInstance()被执行,输出第一行“B被调用”,B.getInstance()方法结束。虽然这时候B的初始化阶段尚未结束,但是解析阶段已经完成,所以getInstance()方法可以被正确执行,但这时候静态字段static B b仍然为null(注意,b.<init>方法还没完呢),所以这个B.getInstance()方法返回值为null,所以A.b为null。
A.<clinit>方法结束,第3步的invokestatic指令正式执行,即A.getInstance()被执行,输出第二行“A被调用”,返回A的实例,这时候B.a不为null了。
B.<clinit>方法结束,第1步的invokestatic指令正式执行,即B.getInstance()被执行,输出第三行“B被调用”
B.test()方法被执行,输出B.a的toString()方法结果,即第四行“A@35ce36”。
A.getInstance()方法被执行,输出第五行“A被调用”。
A.test()方法被执行,输出null,即A.b的值。
这样写应该比较好懂了吧?
但是虚拟机中一个类(<class,classloader>为一个类)只会初始化一次。
发表评论
-
一个优秀的Java程序员必须了解GC机制
2015-01-16 17:04 1618一个优秀的Java程序员必须了解GC的工作原理、如何优化GC ... -
jvm的内存分配及运行机制(转)
2014-12-18 15:13 907http://www.cnblogs.com/200911 ... -
深入Java虚拟机之内存优化
2013-05-16 16:00 961前面一篇文章介绍了Java虚拟机的体系结构和内存模型,既然提 ... -
深入Java虚拟机之虚拟机体系结构
2013-05-16 16:00 961工作以来,代码越写越多,程序也越来越臃肿,效率越来越低,对于 ... -
JAVA虚拟机内存分配与回收机制
2013-05-16 15:19 1055https://www.ibm.com/develope ... -
Java类加载器介绍
2013-04-16 11:19 928类加载器负责把类加载到Java虚拟机(JVM)中。指定类 ... -
JVM加载class文件的原理
2013-03-20 09:50 1421url:http://hxraid.iteye.com/b ... -
Java类加载机制深度分析
2013-03-05 23:00 944Java类加载机制 类加载 ... -
一次Java垃圾收集调优实战(转江南白衣)
2012-10-22 21:19 11611 资料 JDK5.0垃圾收集优化之--Don' ... -
深入java虚拟机(圣思园)
2012-06-06 12:01 16831.Java虚拟机与程序的 ... -
深入java虚拟机
2012-06-06 09:33 1240类的运行步骤: 1.加载(从硬盘到内存)----> ... -
jvm调优
2012-03-18 23:22 1201堆大小设置 JVM 中最大 ... -
用户自定义的类加载器
2012-03-18 16:28 12151、用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩 ... -
Java虚拟机 原理
2012-02-20 14:05 1003Java技术与Java虚拟机 本文转自:http://w ...
相关推荐
1. **类加载子系统**:描述了如何加载、验证、准备、解析和初始化类。 2. **运行时数据区**:包括堆、方法区、栈、本地方法栈和程序计数器,它们分别存储不同类型的运行时数据。 3. **字节码执行引擎**:解释执行...
3. **对象构造**:在分配好内存之后,JVM将执行构造方法,以初始化对象的状态。构造过程包括对对象头和实例数据的初始化。 4. **设置对象头**:对象创建完成后,JVM需要为对象设置必要的标志位,如哈希码、GC年龄等...
初始化阶段负责执行类构造器`<clinit>`方法。 #### 2. 字节码执行引擎 JVM的核心组件之一就是字节码解释器,它负责执行字节码指令。此外,JVM还包含一个即时编译器(JIT Compiler),能够将热点代码编译成本地机器...
加载是找到类的二进制数据,验证确保数据的正确性,准备分配静态变量内存,解析将符号引用转为直接引用,初始化执行类构造器。 3. 字节码执行 JVM通过解释器和即时编译器(如HotSpot的C1和C2编译器)共同作用来...
在深入了解Java虚拟机(JVM)的加载初始化之前,我们先明确一下`Classloader`的角色。简单地说,`Classloader`的主要职责是将编译后的`.class`文件装载到机器的内存中,为后续程序的执行提供必要的条件。这一过程...
初始化阶段是执行类构造器方法的过程。方法是由编译器自动收集类中的类变量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证子方法执行之前,父类的方法已经执行完毕,如果一个类中没有对静态变量赋值也没有...
5. **初始化**:为类的静态变量赋予正确的初始值,执行类构造器方法(`clinit`)的过程。 #### 四、类加载器分类 - **启动类加载器(Bootstrap ClassLoader)**:用于加载核心类库,如`rt.jar`。 - **其他类加载器**...
- **初始化**:执行类构造器`()`方法。 #### 运行时数据区 运行时数据区由以下几个部分组成: - **程序计数器**:记录当前线程所执行的字节码指令地址。 - **Java虚拟机栈**:用于存储局部变量表、操作数栈、动态...
3. **初始化**:执行类构造器`<clinit>`方法,对类进行初始化处理。 #### 内存管理与垃圾回收 内存管理是JVM的重要功能之一,主要涉及对象的创建、存储和销毁。JVM采用分代收集策略,将堆内存分为新生代和老年代。...
静态初始化块是以`static`关键字标识的代码块,它在类被加载到Java虚拟机(JVM)时执行,且只执行一次。静态初始化块常用于设置类级别的变量,或者执行只应执行一次的初始化操作。例如,如果一个类需要在程序运行前...
其中,类的初始化阶段是执行类构造器`()`的地方,负责对类变量进行初始值设置。 #### 字节码解释与JIT编译 Java程序最初以字节码形式运行,由解释器解释执行。为了提高性能,JIT(Just-In-Time)编译器会在运行时将...
Java虚拟机(JVM)是Java程序运行的核心,它的内部机制包括了类的加载、链接、初始化等关键过程。在Java编程中,了解这些过程对于优化程序性能、理解和解决类加载问题至关重要。本文将深入探讨Java虚拟机中的类初始...
- 构造器主体:最后,执行当前类的构造器主体,完成对象的具体初始化。 4. **多线程下的初始化**: - 当多个线程同时尝试初始化同一个类时,Java保证只会执行一次类的初始化过程。这是由JVM的同步机制保证的,...
其中,验证确保字节码的安全性,准备阶段分配静态变量内存,解析处理符号引用,初始化则执行类构造器。 堆内存是JVM中最大的一块内存区域,用于存储对象实例。新生代和老年代是堆内存的两个主要部分,新生代主要...
需要注意的是,静态初始化块只在类被加载时执行一次,而实例初始化块(构造函数)则会在每次创建类的实例时执行。静态变量的初始化是在类加载时完成的,而实例变量的初始化则在对象创建时进行。 在实际开发中,对...
当Java虚拟机(JVM)首次遇到某个类的实例或者静态变量,或者当类的静态方法被调用时,会触发类的加载和初始化。类的初始化主要涉及到以下几个步骤: 1. 类加载:JVM会通过类加载器将类的.class文件加载到内存中。 ...
这两个初始化块的内容会被编译器插入到对应的构造函数和`<clinit>`方法中。 最后,工具在Java代码初始化中的作用不容忽视。例如,IDE如IntelliJ IDEA和Eclipse可以帮助开发者调试和理解初始化流程,通过断点、变量...