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);
    }
}
4
  • 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.) Commented Feb 25, 2015 at 13:24
  • Upvoted for the phrase 'cognitive dissonance' Commented Feb 25, 2015 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 stackoverflow.com/questions/15327417/…) Commented Feb 25, 2015 at 13:49
  • @isnot2bad I have simplified for example. Actually the initialization process debugPaint more complicated. Commented Feb 25, 2015 at 14:21

2 Answers 2

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());
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

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).
@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.
@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?
@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.
@Mixer no, removing = null won't help as this is implicit. Just don't call overridden methods inside a constructor! Never!
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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.