一道关于Java类初始化的难题

wingardium 2010-03-25 05:10:44
请看下面两个程序:
(1)
public class InitPuzzle {
private static boolean initialized = false;
private static Thread t = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
initialized = true;
}
});

static {
t.start();
System.out.println(Thread.currentThread());

try{
Thread.sleep(1000);
System.out.println(initialized);
}catch (InterruptedException e){
throw new AssertionError(e);
}
}

public InitPuzzle(){
System.out.println("Initialization is finished!");
}

public static void main(String[] args){
new InitPuzzle();
}
}

=============================================

(2)

public class InitPuzzle {
private boolean initialized = false;
private Thread t = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
initialized = true;
}
});

{
t.start();
System.out.println(Thread.currentThread());

try{
Thread.sleep(1000);
System.out.println(initialized);
}catch (InterruptedException e){
throw new AssertionError(e);
}
}

public InitPuzzle(){
System.out.println("Initialization is finished!");
}

public static void main(String[] args){
new InitPuzzle();
}
}

这两个类的差别只在前者多了static,但是运行输出结果为什么不一样呢?
...全文
670 51 打赏 收藏 转发到动态 举报
写回复
用AI写文章
51 条回复
切换为时间正序
请发表友善的回复…
发表回复
wst004 2011-10-09
  • 打赏
  • 举报
回复
我想匿名类要使用外部类,必须等类的初始化完成吧。所以t thread is blocked at initialized=true
echolxl2010 2010-04-07
  • 打赏
  • 举报
回复
还是新手,进来学习了!
gaofan1994 2010-04-07
  • 打赏
  • 举报
回复
public class InitPuzzle {
private static boolean initialized = false;
private static Thread t = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
initialized = true;
}
});

static {
t.start();
System.out.println(Thread.currentThread());

try{
Thread.sleep(1000);
System.out.println(initialized);
}catch (InterruptedException e){
throw new AssertionError(e);
}
}

public InitPuzzle(){
System.out.println("Initialization is finished!");
}

public static void main(String[] args){
new InitPuzzle();
}
}

=============================================

(2)

public class InitPuzzle {
private boolean initialized = false;
private Thread t = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
initialized = true;
}
});

{
t.start();
System.out.println(Thread.currentThread());

try{
Thread.sleep(1000);
System.out.println(initialized);
}catch (InterruptedException e){
throw new AssertionError(e);
}
}

public InitPuzzle(){
System.out.println("Initialization is finished!");
}

public static void main(String[] args){
new InitPuzzle();
}
}

这两个类的差别只在前者多了static,但是运行输出结果为什么不一样呢?



对我有用[0] 丢个板砖[0] 引用 举报 管理 TOP 回复次数:48

sunboylg

(sunboylg)

等 级:
#1楼 得分:0回复于:2010-03-25 17:17:11static 是静态的意思,也就是说它修饰的值是改变不了的,下面的第二个类里修饰属性时候没有用static,所以它的值是可以改变的!


wingardium 2010-04-07
  • 打赏
  • 举报
回复
[Quote=引用 47 楼 cdj8887 的回复:]
static 是类内的静态区域,当你用到或构造对象的时候首先第一触发的就是它
[/Quote]

static的叫类初始化块,构造对象那叫实例初始化。你搞混了
cdj8887 2010-04-06
  • 打赏
  • 举报
回复
static 是类内的静态区域,当你用到或构造对象的时候首先第一触发的就是它
gaokangstudy 2010-04-06
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 yzb123 的回复:]
1 类被加载的时候首先运行STATIC块内的语句,也就是先于构造器的调用
2 静态修饰的变量,是指该变量被所有的该类的对象共享。其存储的位置是在 内存的方法区。
注意 静态变量在类加载的时候初始化的
[/Quote]



说的完全正确!
wingardium 2010-04-06
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 hongke1490 的回复:]
怀疑是不是static块对static变量是同步的?
[/Quote]

不是。而且没有“static块对static变量”这种提法
rqq0609 2010-04-02
  • 打赏
  • 举报
回复
没看懂啊,哈
wingardium 2010-04-02
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 hardycheng 的回复:]
我自己加了一些断点测了一下;
由于是Thread
所以在 t.start()之后不一定立刻执行t.run();

执行顺序:
static {
1 ======= t.start();
2 ========System.out.println(Thread.currentThread());

try{
3==========Thread.sleep(1000);
4====……
[/Quote]

如果你修改这个题目的代码了,当然打印结果会如你所愿。
xihuanyatou 2010-04-02
  • 打赏
  • 举报
回复
只看不参与讨论
铁匠梁老师 2010-04-02
  • 打赏
  • 举报
回复
static 先于构造函数执行
hardycheng 2010-04-02
  • 打赏
  • 举报
回复
我自己加了一些断点测了一下;
由于是Thread
所以在 t.start()之后不一定立刻执行t.run();

执行顺序:
static {
1 ======= t.start();
2 ========System.out.println(Thread.currentThread());

try{
3==========Thread.sleep(1000);
4==========System.out.println(initialized);
}catch (InterruptedException e){
throw new AssertionError(e);
}
}

public void run() {
5 =========System.out.println(Thread.currentThread());
6 ==========initialized = true;
}


所以是和执行顺序有关的。

你也可以试一下下面代码:

private static Thread t = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
initialized = true;
System.out.println("Thread -- t : " + InitPuzzle.initialized);
t_2.start();
}
}
);
private static Thread t_2 = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());

System.out.println("Thread t2: " + InitPuzzle.initialized);
}
}
);


t_2中的System.println中的InitPuzzle.initialized值为true;
hongke1490 2010-04-02
  • 打赏
  • 举报
回复
把程序改成这样试了一下

public class InitTest {
private static boolean initialized = false;
private static int initI = 0;
private static Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("1");
initI = 2;
System.out.println(initI);
}
});

static {
t.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new AssertionError(e);
}
System.out.println(initialized);

}

public InitTest() {
System.out.println("Initialization is finished!");
}

public static void main(String[] args) {
new InitTest();
}
}

怀疑是不是static块对static变量是同步的?
goto4c00 2010-04-02
  • 打赏
  • 举报
回复
我想LZ困惑的是第一个事例代码,因为初始线程等待1000毫秒的目的是让t先执行
完毕。并且从结果来看t确实很快的启动了(初始线程的打印后立即出现了t线程的
打印,然后大概1秒的时间打印出“false”。看起来t线程对“initialized”的
修改无效。

首先要说明这个地方和对象的初始化无关,如果我们把main函数中的代码改为如下:
try{
Class.forName("InitPuzzle");
}catch (Exception e){

}

这里没有实例化对象,只是加载了类,执行的结果除了没有构造函数里面的打印外其他都一样

为了找到问题,把t线程修改一下,在修改 initialized 后加一个打印

private static Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("t:" + Thread.currentThread());
initialized = true;
System.out.println("u:" + initialized);
}
});

执行结果为

Thread[main,5,main]
t:Thread[Thread-0,5,main]
false
u:true

“U:true”说明t线程的修改是成功的,但它却出现了在“false”后面。
所以执行流程变成了 “初始线程” -〉t线程 -〉“初始线程” -〉t线程,看来t线程在执行
initialized = true;时被阻塞住了。你可以增大初始线程sleep的时间,结果不受影响。
只是为什么被“阻塞”我也不能解释。
wingardium 2010-04-02
  • 打赏
  • 举报
回复
[Quote=引用 41 楼 hardycheng 的回复:]
引用 39 楼 wingardium 的回复:

引用 36 楼 hardycheng 的回复:
我自己加了一些断点测了一下;
由于是Thread
所以在 t.start()之后不一定立刻执行t.run();

执行顺序:
static {
1 ======= t.start();
2 ========System.out.println(Thread.currentThrea……
[/Quote]

"所以在 t.start()之后不一定立刻执行t.run();" 这没有问题,可是你别忘记了static代码块中有Thread.sleep(1000); 1秒钟对于jvm来说是很长的一段时间了,主线程sleep了1秒钟足够t线程跑完了。如果你觉得1秒不够,你可以改成主线程休眠10秒,1分钟,看看结果如何呢?
hardycheng 2010-04-02
  • 打赏
  • 举报
回复
[Quote=引用 39 楼 wingardium 的回复:]

引用 36 楼 hardycheng 的回复:
我自己加了一些断点测了一下;
由于是Thread
所以在 t.start()之后不一定立刻执行t.run();

执行顺序:
static {
1 ======= t.start();
2 ========System.out.println(Thread.currentThread());

try{
3==========……
[/Quote]


代码我没修改 只不过我是按照顺序把代码贴了一下

你自己可以试一下,

37L说得对的,是陷于构造执行。

我该代码测试还有意思吗,这孩子 ~~!
wingardium 2010-04-01
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 mutoujuelian 的回复:]
为什么在第二个里面设一个断点, 会得到不同的结果啊?
[/Quote]

这就是本题的难点所在啊!
hanweiit007 2010-03-31
  • 打赏
  • 举报
回复
挂分啊!!!!!!!
py330316117 2010-03-31
  • 打赏
  • 举报
回复
(1)before
Thread[main,5,main]
false
Initialization is finished!
after
(2)before
after
Thread[main,5,main]
true
Initialization is finished!
这是你改了之后的结果,如果像你说的那after的打印顺序你怎么解释,java的结果输出顺序不能只看代码的书写顺序,特别是线程这个地方,如果你想凭着人脑就分析虚拟机那是痴心妄想,这个地方不同机器的运行结果是不一样的。后面我说函数初始化实际上就是指类初始化函数
狂想者 2010-03-31
  • 打赏
  • 举报
回复
学习啊!!!!!!!!!!!!!!!!!!
加载更多回复(29)

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧