13

Every one of you know about this feature of JMM, that sometimes reference to object could receive value before constructor of this object is finished.

In JLS7, p. 17.5 final Field Semantics we can also read:

The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. (1)

And just after that in JLS the example follows, which demonstrate, how non-final field is not guaranteed to be initialized (1Example 17.5-1.1) (2):

class FinalFieldExample { 
    final int x; 
    int y; 

    static FinalFieldExample f;

    public FinalFieldExample() { 
        x = 3; 
        y = 4; 
    } 

    static void writer() { 
        f = new FinalFieldExample(); 
    } 

    static void reader() { 
       if (f != null) { 
           int i = f.x; // guaranteed to see 3 
           int j = f.y; // could see 0 
       } 
    } 
}

Also, in this question-answer Mr. Gray wrote:

If you mark the field as final then the constructor is guaranteed to finish initialization as part of the constructor. Otherwise you will have to synchronize on a lock before using it. (3)


So, the question is:

1) According to statement (1) we should avoid sharing reference to immutable object before its constructor is finished

2) According to JLS's given example (2) and conclusion (3) it seems, that we can safely share reference to immutable object before its constructor is finished, i.e. when all its fields are final.

Isn't there some contradiction?


EDIT-1: What I exactly mean. If we will modify class in example such way, that field y will be also final (2):

class FinalFieldExample { 
    final int x; 
    final int y; 
    ...

hence in reader() method it will be guaranteed, that:

if (f != null) { 
int i = f.x; // guaranteed to see 3
int j = f.y; // guaranteed to see 4, isn't it???

If so, why we should avoid writing reference to object f before it's constructor is finished (according to (1)), when all fields of f are final?

Community
  • 1
  • 1
Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • see also: [Final Fields Semantics in Threads](http://stackoverflow.com/questions/9495159/final-fields-semantics-in-threads) – gnat Dec 06 '13 at 06:07

4 Answers4

7

Isn't there some contradiction [in the JLS around constructors and object publishing]?

I believe these are slightly different issues that are not contradictory.

The JLS reference is taking about storing an object reference in a place where other threads can see it before the constructor is finished. For example, in a constructor, you should not put an object into a static field that is used by other threads nor should you fork a thread.

  public class FinalFieldExample {
      public FinalFieldExample() {
         ...
         // very bad idea because the constructor may not have finished
         FinalFieldExample.f = this;
         ...
      }
  }

You shouldn't start the thread in a construtor either:

  // obviously we should implement Runnable here
  public class MyThread extends Thread {
      public MyThread() {
         ...
         // very bad idea because the constructor may not have finished
         this.start();
      }
  }

Even if all of your fields are final in a class, sharing the reference to the object to another thread before the constructor finishes cannot guarantee that the fields have been set by the time the other threads start using the object.

My answer was talking about using an object without synchronization after the constructor had finished. It's a slightly different question although similar with regards to constructors, lack of synchronization, and reordering of operations by the compiler.

In JLS 17.5-1 they don't assign a static field inside of the constructor. They assign the static field in another static method:

static void writer() {
    f = new FinalFieldExample();
}

This is the critical difference.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Well, you wrote: *For example, you should not put an object into a static field that is used by other threads*. Take a look at the `Example 17.5-1.` from JLS7. They do exactly this: `static FinalFieldExample f; ... f = new FinalFieldExample();` and guarantee that `final` `f.x` will be properly initialized. – Andremoniy Feb 01 '13 at 19:49
  • So they set that static from _within_ the constructor @Andremoniy? That's the issue. – Gray Feb 01 '13 at 19:58
  • they do this in some static method: `static void writer() { f = new FinalFieldExample(); }`. – Andremoniy Feb 01 '13 at 19:59
  • Right. This is different from setting the static field from _within_ the `FinalFieldExample` constructor. That's what I'm talking about @Andremoniy. – Gray Feb 01 '13 at 20:06
  • Sorry, but I still don't understand. You wrote: *Even if all of your fields are final in a class, sharing the reference to the object to another thread before the constructor finishes cannot guarantee that the final fields have been set by the time the other threads start using the object*. But in the example 17.5-1. they really do share object's reference among threads before this constructor is finished. Why? – Andremoniy Feb 01 '13 at 20:14
  • No they don't @Andremoniy. They assign the static field in another static method. I've edited my answer. – Gray Feb 01 '13 at 20:19
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/23804/discussion-between-andremoniy-and-gray) – Andremoniy Feb 01 '13 at 20:21
  • @Gray: There is one more line written in the JLS specification which is: *Because the writer method writes f after the object's constructor finishes, the reader method will be guaranteed to see the properly initialized value for f*. My question is : how JVM ensures that the writer method writes f only after the constructor is concluded??? *What is preventing the f to be written before the object's construction is completed???* – Mac Aug 11 '14 at 00:45
4

In the full example

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
    } 

    static void writer() {
        f = new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}

As you can see, f is not set until after the constructor returns. This means f.x is safe because it is final AND the constructor has returned.

In the following example, neither value is guarenteed to be set.

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
        f = this; // assign before finished.
    } 

    static void writer() {
        new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // not guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}

According to statement (1) we should avoid sharing reference to immutable object before its constructor is finished

You should not allow a reference to an object escape before it is constructed for a number of reason (immutable or other wise) e.g. the object might throw an Exception after you have store the object.

According to JLS's given example (2) and conclusion (3) it seems, that we can safely share reference to immutable object, i.e. when all its fields are final.

You can safely share a reference to an immutable object between threads after the object has been constructed.

Note: you can see the value of an immutable field before it is set in a method called by a constructor.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 2
    Is your first line missing a _not_ Peter? – Gray Feb 01 '13 at 19:56
  • Still do not understand. I just edited my question. In my 2) thesis I mean, that according to (2) and (3) we can safely share reference **before** constructor is finished. It directly follows from example (2). Doesn't it? – Andremoniy Feb 01 '13 at 19:57
  • @Andremoniy I don't see how you come to that conclusion. It states that final gives some guarantees at the end of construction and non-final doesn't. It doesn't suggest you have any guarantees before the end of construction. – Peter Lawrey Feb 01 '13 at 20:00
  • @PeterLawrey well, consider class, where all fields are `final`. Will this object be safe to share its reference before its constructor is finished? According to example it will. Because I don't see any difference between my imagined object and object from example, where field `y` will be `final`. – Andremoniy Feb 01 '13 at 20:03
  • @Andremoniy You must be reading different code to me. When I look at the full code, I don't see this at all. – Peter Lawrey Feb 01 '13 at 20:13
  • I've just edited my question one more time. Please, read. Will this be more clear what I mean? :) – Andremoniy Feb 01 '13 at 20:20
  • 1
    @Andremoniy I have changed the example to show how this could be a problem. – Peter Lawrey Feb 01 '13 at 20:43
  • *As you can see, f is not set until after the constructor returns*.. How can we be sure of this? What is preventing the `f` to be written before the construction is completed? – Mac Aug 11 '14 at 00:53
3

Construct exit plays an important role here; the JLS says "A freeze action on final field f of o takes place when c exits". Publishing the reference before/after constructor exit are very different.

Informally

1 constructor enter{

2   assign final field

3   publish this

4 }constructor exit

5 publish the newly constructed object

[2] cannot be reordered beyond constructor exit. so [2] cannot be reordered after [5].

but [2] can be reordered after [3].

irreputable
  • 44,725
  • 9
  • 65
  • 93
1

Statement 1) does not say what you think it does. If anything, I would rephrase your statement:

1) According to statement (1) we should avoid sharing reference to immutable object before its constructor is finished

to read

1) According to statement (1) we should avoid sharing reference to mutable object before its constructor is finished

where what I mean by mutable is an object that has ANY non-final fields or final references to mutable objects. (have to admit I'm not 100% that you need to worry about final references to mutable objects, but I think I'm right...)


To put it another way, you should distinguish between:

  • final fields (immutable parts of a possibly immutable object)
  • non-final fields who have to be initialized before anyone interacts with this object
  • non-final fields that do not have to be initialized before anyone interacts with this object

The second one is the problem spot.

So, you can share references to immutable objects (all fields are final), but you need to use caution with objects that have non-final fields that HAVE to be initialized before the object can be used by anyone.

In other words, for the edited JLS example you posted where both fields are final, int j = f.y; is guaranteed to be final. But what that means is that you do NOT need to avoid writing the reference to object f, because it'll always be in a correctly initialized state before anyone could see it. You do not need to worry about it, the JVM does.

sharakan
  • 6,821
  • 1
  • 34
  • 61
  • Nop, in statement (1) is said exactly about set of `final` fields. – Andremoniy Feb 01 '13 at 19:51
  • @Andremoniy in your question 1), did you mean to say mutable, or immutable? Because what statement 1) boils down to is that you need to use caution sharing ***mutable*** objects. – sharakan Feb 01 '13 at 19:52
  • If all fields in object are `final` we can consider this object as `immutable`. And this is a case which stmt (1) talks about. Could you contradict? – Andremoniy Feb 01 '13 at 19:54
  • @Andremoniy no, I 100% agree with that statement. What I disagree with is the part of your question that reads "1) According to statement (1) we should avoid sharing reference to immutable object...". That should read "...reference to ***mutable*** object..." – sharakan Feb 01 '13 at 19:55
  • Well, in statement (1) is talking about object with `final` fields. Isn't it? And there is talking about, that we should NOT share this reference before constructor is finished. Isn't it? – Andremoniy Feb 01 '13 at 19:58
  • One final field, one NOT final. ie, the object is ***mutable***. – sharakan Feb 01 '13 at 19:58
  • Please, read: *If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields*. Ones more: *If this is followed ... blablabla ... of that object's final fields*. They talk about `final` fields. Don't they? – Andremoniy Feb 01 '13 at 20:00
  • in any way, could we consider class where **all fields are** `final`? Will it be particular case for that's statement (1)? – Andremoniy Feb 01 '13 at 20:05
  • @Andremoniy If there is a class where all fields are `final`, I would consider the class immutable (as long as those fields are of immutable classes, etc), and it would be entirely safe to publish this object before the constructor returns. – sharakan Feb 01 '13 at 20:07
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/23803/discussion-between-andremoniy-and-sharakan) – Andremoniy Feb 01 '13 at 20:10