简体   繁体   中英

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". From the constructor of the parent "A" is called an abstract function "init" of the class "B". It initializes a debugPaint member of the class "B".

Then, it creates a Thread which periodically calls the function postDraw . The problem is that if I assign private volatile Paint debugPaint=null function postDraw receive debugPaint member as null . Although as I can see in the debugger initialization was successful previously. If the assignment to null is not done, then everything works. private volatile Paint debugPaint ; What is the problem?

ps Time between init and postDraw is a lot for a few seconds.

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. That constructor calls B.init() which sets debugPaint to point to a new Paint object. Then, after the A() constructor finishes, the default B() constructor is called...

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.

In Java it is not advisable to start threads from a constructor. Instead, init() should be called after construction. Should be OK then.

See Java: starting a new thread in a constructor

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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