从另一个线程调用时,变量为null

时间:2015-02-25 13:22:45

标签: java multithreading variables initialization

请向我解释变量的奇怪行为。 从主线程创建类“B”的实例。 从父“A”的构造函数称为类“B”的抽象函数“init”。 它初始化类“B”的 debugPaint 成员。

然后,它创建一个Thread,定期调用函数 postDraw 。 问题是如果我将私有volatile Paint debugPaint = null 函数 postDraw 接收 debugPaint 成员指定为 null 。虽然我可以在调试器中看到初始化是成功的。 如果没有完成对null的赋值,则一切正常。 private volatile Paint debugPaint ; 有什么问题?

p.s init和postDraw之间的时间很长几秒钟。

public class A{

  public A()
  {
    init();
  }

  public void draw(Canvas canvas)
  {
    //some code....
   postDraw(canvas);
  }

  abstract public void postDraw(Canvas canvas);
  abstract public void init();
}


public class B extends A{

    private volatile Paint  debugPaint=null;//=null problem! not =null ok!

    @Override
    public void init()
    {
        debugPaint=new Paint();
    }


    @Override
    public void postDraw(Canvas canvas)
    {
       canvas.drawRect(0,0,128,128,debugPaint);
    }
}

2 个答案:

答案 0 :(得分:3)

您的问题与线程无关。

以下示例是一个演示此问题的完整程序:

main()例程创建一个新的B实例时,它首先调用A()构造函数。该构造函数调用B.init(),它将debugPaint设置为指向新的Paint对象。然后,在A()构造函数完成后,调用默认 B()构造函数...

class Paint {
}

class Canvas {
}

abstract class A{

  public A()
  {
    System.out.println("A.<init>() entered");
    init();
    System.out.println("A.<init>() exit");
  }

  public void draw(Canvas canvas)
  {
    //some code....
   postDraw(canvas);
  }

  abstract public void postDraw(Canvas canvas);
  abstract public void init();
}


class B extends A{

    private volatile Paint  debugPaint=null;   //this assignment happens in the default B() constructor

    @Override
    public void init()
    {
        System.out.println("B.init() entered");
        debugPaint=new Paint();
        System.out.println("B.init() exit");
    }


    @Override
    public void postDraw(Canvas canvas)
    {
       System.out.println("debugPaint=" + debugPaint);
    }
}

public class Foobar {
    public static void main(String[] args) {
        B b = new B();
        b.draw(new Canvas());
    }
}

答案 1 :(得分:1)

我认为这里的问题是新的线程在构造函数中声明(尽管是间接的),因此在新线程启动时A不会被完全实例化。

在Java中,不建议从构造函数启动线程。相反,应该在构造之后调用init()。应该没问题。

请参阅Java: starting a new thread in a constructor