本帖最后由 qzhforthelife 于 2012-11-13 00:05:55 编辑

解决方案 »

  1.   

    反例代码: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.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)
      

  2.   

    构造方法对应的<init>只要没有return,就表示还没有执行完,在调用start之后,CPU可能碰巧就立即就切换去执行新线程了,而构造方法还没有执行结束,对象也就还没有构建完整
      

  3.   

    这跟类的构造是有关系的。比方说有个类:
    pulbic class A{
        private String t="hello";
        private Integer p=4;
        ....................
    }
    那么当javac 去编译这个类时,会把这两个变量放到<init>方法里面去。构造函数的所有操作也将放大这个方法里面。也就是说你看到的启动线程是最后一句。经过编译器后,就不一定是最后一句了。而且现代的编译器都有编译优化,对调赋值语句的顺序也是有可能的。
    当你在构造函数里面启动一个线程以后,当前对象的this引用就泄漏给这个新启动的线程了。当如上面所说的,这个对象很可能还没有构造完。比如A类中的两个成员变量还没有赋值,this引用就泄漏给了新启动的线程。那么通过this引用去获取 A类 中的 t对象将是空。而不是我们认为的"hello"。这是不安全的对象发布模式。所以不建议在构造函数中启动线程。