编程思想中关于线程启动的一个疑问 本帖最后由 qzhforthelife 于 2012-11-13 00:05:55 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 反例代码:public class SelfManaged implements Runnable { private int countDown = 5; private Thread t = new Thread(this); public SelfManaged() { t.start(); } public String toString() { return Thread.currentThread().getName() + "(" + countDown + "), "; } public void run() { while(true) { System.out.print(this); if( --countDown == 0 ) return; } } public static void main(String[] args) { for(int i = 0; i < 5; i++) new SubSelfManaged(i); }}class SubSelfManaged extends SelfManaged { private Integer id; SubSelfManaged(int id) { this.id = id; } @Override public String toString() { return super.toString() + " : " + id.intValue(); }}运行时抛出 NullPointerException:run:Exception in thread "Thread-0" java.lang.NullPointerExceptionThread-2(5), : 2Thread-2(4), : 2Thread-2(3), : 2Thread-2(2), : 2Thread-2(1), : 2Thread-4(5), : 4Thread-4(4), : 4Thread-4(3), : 4Thread-4(2), : 4Thread-4(1), : 4Thread-1(5), : 1Thread-1(4), : 1Thread-1(3), : 1Thread-1(2), : 1Thread-1(1), : 1Thread-3(5), : 3Thread-3(4), : 3Thread-3(3), : 3Thread-3(2), : 3Thread-3(1), : 3 at SubSelfManaged.toString(SubSelfManaged.java:19) at java.lang.String.valueOf(String.java:2826) at java.io.PrintStream.print(PrintStream.java:633) at SelfManaged.run(SelfManaged.java:20) at java.lang.Thread.run(Thread.java:662)BUILD SUCCESSFUL (total time: 0 seconds) 构造方法对应的<init>只要没有return,就表示还没有执行完,在调用start之后,CPU可能碰巧就立即就切换去执行新线程了,而构造方法还没有执行结束,对象也就还没有构建完整 这跟类的构造是有关系的。比方说有个类:pulbic class A{ private String t="hello"; private Integer p=4; ....................}那么当javac 去编译这个类时,会把这两个变量放到<init>方法里面去。构造函数的所有操作也将放大这个方法里面。也就是说你看到的启动线程是最后一句。经过编译器后,就不一定是最后一句了。而且现代的编译器都有编译优化,对调赋值语句的顺序也是有可能的。当你在构造函数里面启动一个线程以后,当前对象的this引用就泄漏给这个新启动的线程了。当如上面所说的,这个对象很可能还没有构造完。比如A类中的两个成员变量还没有赋值,this引用就泄漏给了新启动的线程。那么通过this引用去获取 A类 中的 t对象将是空。而不是我们认为的"hello"。这是不安全的对象发布模式。所以不建议在构造函数中启动线程。 Runtime.getRuntime().exec(command);如何使用相对exe路径 java 打包问题 谁有 << JavaScript核心技术 >>????????? 怎样写权限设置,通过用户权限控制菜单??? [共享]java面试题_3 (大家看看有帮助么?) 各位武林高手小弟这下有问题了!!! 刷新jtable 关于SQLException处理的讨论!(相信很多人忽略这个问题) 如何控制Frame中的组件大小,当用鼠标拖动改变frame大小时 Java的具体应用? 菜鸟 求助 菜鸟问个关于报文的菜鸟问题
private Thread t = new Thread(this); public SelfManaged() {
t.start();
} public String toString() {
return Thread.currentThread().getName()
+ "(" + countDown + "), ";
} public void run() {
while(true) {
System.out.print(this);
if( --countDown == 0 )
return;
}
} public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new SubSelfManaged(i);
}
}class SubSelfManaged extends SelfManaged {
private Integer id;
SubSelfManaged(int id) {
this.id = id;
}
@Override
public String toString() {
return super.toString() + " : " + id.intValue();
}
}
运行时抛出 NullPointerException:run:
Exception in thread "Thread-0" java.lang.NullPointerException
Thread-2(5), : 2Thread-2(4), : 2Thread-2(3), : 2Thread-2(2), : 2Thread-2(1), : 2Thread-4(5), : 4Thread-4(4), : 4Thread-4(3), : 4Thread-4(2), : 4Thread-4(1), : 4Thread-1(5), : 1Thread-1(4), : 1Thread-1(3), : 1Thread-1(2), : 1Thread-1(1), : 1Thread-3(5), : 3Thread-3(4), : 3Thread-3(3), : 3Thread-3(2), : 3Thread-3(1), : 3 at SubSelfManaged.toString(SubSelfManaged.java:19)
at java.lang.String.valueOf(String.java:2826)
at java.io.PrintStream.print(PrintStream.java:633)
at SelfManaged.run(SelfManaged.java:20)
at java.lang.Thread.run(Thread.java:662)
BUILD SUCCESSFUL (total time: 0 seconds)
pulbic class A{
private String t="hello";
private Integer p=4;
....................
}
那么当javac 去编译这个类时,会把这两个变量放到<init>方法里面去。构造函数的所有操作也将放大这个方法里面。也就是说你看到的启动线程是最后一句。经过编译器后,就不一定是最后一句了。而且现代的编译器都有编译优化,对调赋值语句的顺序也是有可能的。
当你在构造函数里面启动一个线程以后,当前对象的this引用就泄漏给这个新启动的线程了。当如上面所说的,这个对象很可能还没有构造完。比如A类中的两个成员变量还没有赋值,this引用就泄漏给了新启动的线程。那么通过this引用去获取 A类 中的 t对象将是空。而不是我们认为的"hello"。这是不安全的对象发布模式。所以不建议在构造函数中启动线程。