Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java: why should this not be allowed to escape the constructor?

In JCIP, section 3.2.1 "Safe Constructor Practices", there is a warning against leaking this to another thread from the constructor, "even if the publication is the last statement in the constructor." That last part seems too strong to me, and it's provided with no justification. What is it that happens after construction that I must be so careful to avoid? Are there exceptions? I'm interested because I recently submitted some code in which I did this very thing, and I want to decide whether there is justification to go back through and refactor.

like image 480
philo Avatar asked Nov 21 '12 23:11

philo


People also ask

What is the leaking of this constructor?

Leaking this from the constructor thus means that the external world gets access to an object which is not yet fully constructed. This may not necessarily lead to problems in a a single-threaded program (although it is possible, but the problem is much more obvious in this case).

Can we start a thread in constructor?

There's nothing inherently wrong with creating a Thread inside a constructor. However, it's highly discouraged to start it immediately, as most of the time, we end up with an escaped this reference, either explicitly or implicitly.


2 Answers

As far as Java memory model is concerned, the constructor exit plays a role in final field semantics, therefore there's a difference whether a statement is before or after constructor exit.

This works                         This doesn't work
-------------------------------------------------------------

static Foo shared;                 static Foo shared;

class Foo                          class Foo
{                                  {   
    final int i;                       final int i; 
    Foo()                              Foo() 
    {                                  {
        i = 1;                             i = 1;
                                           shared = this;  
    }                                  }
}                                  }

shared = new Foo();                new Foo();

(Note: shared is not volatile; the publication is through data race.)

The only difference between the 2 examples is assigning shared before or after constructor exit. In the second example, i=1 is allowed to be reordered after the assignment.

However, if the publication is a synchronized action, e.g. through a volatile variable, then it's ok; other threads will observe a fully initialized object; the fields don't even have to final.

Publication through data race (or doing anything through data race) is a very tricky business that requires very careful reasoning. If you avoid data race, things are much simpler. If your code contains no data race, there's no difference between leaking this immediately before constructor exit, and publishing it immediately after constructor exit.

like image 75
irreputable Avatar answered Oct 10 '22 17:10

irreputable


You should never leak this from a constructor at any point, "even [...] in the last statement." Since this isn't fully constructed some very odd things can happen. See this SO answer on a very similar question.

like image 33
Andrew White Avatar answered Oct 10 '22 16:10

Andrew White