简体   繁体   English

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

[英]Variable is null when called from another thread

Please explain to me the strange behavior of the variable. 请向我解释该变量的奇怪行为。 From the main thread creates an instance of the class "B". 从主线程创建类“ B”的实例。 From the constructor of the parent "A" is called an abstract function "init" of the class "B". 在父级“ A”的构造函数中,该类称为“ B”类的抽象函数“ init”。 It initializes a debugPaint member of the class "B". 它初始化类“ B”的debugPaint成员。

Then, it creates a Thread which periodically calls the function postDraw . 然后,它创建一个线程,该线程定期调用函数postDraw The problem is that if I assign private volatile Paint debugPaint=null function postDraw receive debugPaint member as null . 问题是,如果我分配了私有易失性Paint debugPaint = null函数postDraw, 则将debugPaint成员接收为null Although as I can see in the debugger initialization was successful previously. 尽管正如我在调试器中看到的那样,初始化之前已成功完成。 If the assignment to null is not done, then everything works. 如果未完成对null的赋值,则一切正常。 private volatile Paint debugPaint ; 专用volatile Paint debugPaint ; What is the problem? 问题是什么?

ps Time between init and postDraw is a lot for a few seconds. ps 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);
    }
}

Your problem has nothing to do with threads. 您的问题与线程无关。

The example below is a complete program that demonstrates the problem: 下面的示例是一个完整的程序,演示了此问题:

When the main() routine creaetd a new B instance, it first calls the A() constructor. main()例程创建一个新的B实例时,它首先调用A()构造函数。 That constructor calls B.init() which sets debugPaint to point to a new Paint object. 该构造函数调用B.init(),该函数将debugPaint设置为指向新的Paint对象。 Then, after the A() constructor finishes, the default B() constructor is called... 然后,在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());
    }
}

I think the problem here is that new threads are stated in the constructor (albeit indirectly), so that A is not completely instantiated when the new thread starts. 我认为这里的问题是新线程在构造函数中声明(尽管是间接地),所以当新线程启动时A不会完全实例化。

In Java it is not advisable to start threads from a constructor. 在Java中,建议不要从构造函数启动线程。 Instead, init() should be called after construction. 相反,应在构造后调用init()。 Should be OK then. 那应该可以。

See Java: starting a new thread in a constructor 请参阅Java:在构造函数中启动新线程

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM