1

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?

p.s 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);
    }
}
Mixer
  • 1,292
  • 3
  • 22
  • 41
  • 3
    Please post a short but *complete* program demonstrating the probelm. We've only got part of the code here. (Also, please follow Java naming conventions in sample code, to avoid cognitive dissonance.) – Jon Skeet Feb 25 '15 at 13:24
  • Upvoted for the phrase 'cognitive dissonance' – NickJ Feb 25 '15 at 13:44
  • 2
    Why don't you use field initialization, i.e. `private final Paint debugPaint = new Paint();`? Btw.: The constructor should never call abstract or overridable methods! (See http://stackoverflow.com/questions/15327417/is-it-ok-to-call-abstract-method-from-constructor-in-java) – isnot2bad Feb 25 '15 at 13:49
  • @isnot2bad I have simplified for example. Actually the initialization process debugPaint more complicated. – Mixer Feb 25 '15 at 14:21

2 Answers2

3

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());
    }
}
Solomon Slow
  • 25,130
  • 5
  • 37
  • 57
  • I fully agree with this answer: this has nothing to do with threads. No virtual method (like `init()` here) should be called inside constructors. The solution here is just to have `B` calling `init()` (which is not a virtual method, but only a local helper). – T.Gounelle Feb 25 '15 at 14:01
  • @AbbéRésina All methods in Java are 'virtual' methods: Even if class A declared a concrete init() method, the init() call in the A() constructor still would call B.init(). Any method that you call from a constructor should be declared `final`. – Solomon Slow Feb 25 '15 at 14:06
  • @jameslarge Thank you. init is called, not only from the constructor and so I realized through abstract. Would it be sufficient to remove =null to avoid this situation? – Mixer Feb 25 '15 at 14:11
  • @jameslarge, agreed. what I meant is there is no use to have an `abstract init()` in class `A`, and put the `B` local helper init() as `final`. – T.Gounelle Feb 25 '15 at 14:16
  • @Mixer no, removing `= null` won't help as this is implicit. Just don't call overridden methods inside a constructor! Never! – isnot2bad Feb 25 '15 at 14:44
1

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

Community
  • 1
  • 1
NickJ
  • 9,380
  • 9
  • 51
  • 74