1

I am look into the book "Java Concurrency in Practice" and found really hard to believe below quoted statement (But unfortunately it make sense).

http://www.informit.com/store/java-concurrency-in-practice-9780321349606

Just wanted to get clear about this 100%

public class Holder {
    private int n;
    public Holder(int n) { this.n = n; }
    public void assertSanity() {
      if (n != n)
       throw new AssertionError("This statement is false.");
      }
}

While it may seem that field values set in a constructor are the first values written to those fields and therefore that there are no "older" values to see as stale values, the Object constructor first writes the default values to all fields before subclass constructors run. It is therefore Possible to see the default value for a field as a stale value

Regarding bolded statement in above,

I am aware that the behaviour BUT now it is clear that this calling hierarchy of constructors is NOT guarantee to be ATOMIC (calling super constructors in single synchronised block that is guarded by a lock), but what would be the solution? imagine a class hierarchy that has more than one level (even it is not recommended, lets assume as it is possible). The above code snippest is a kind of a prototype that we see everyday in most of the projects.

Cœur
  • 37,241
  • 25
  • 195
  • 267
nish1013
  • 3,658
  • 8
  • 33
  • 46
  • Multiple inheritance in Java is not possible. In languages with multiple inheritance there are constructs that resolve the ambiguity of having the same field in two or more super classes. If we are discussing Java I still do not understand what do you mean by "guaranteed to be ATOMIC" ? – M.Sameer Oct 04 '13 at 11:26
  • @M.Sameer edited wording to be correct ragarding inheritance. What meant was class hirachy with more than on level – nish1013 Oct 04 '13 at 11:30
  • What does the above example show? Are you saying that you might get the AssertionError out of it? That's hard to believe for me. – Jan Zyka Oct 04 '13 at 11:39
  • @JanZyka that is what book says , the statement is quoted from the book – nish1013 Oct 04 '13 at 12:15
  • 1
    Already discussed in SO: http://stackoverflow.com/questions/1621435/not-thread-safe-object-publishing and also http://stackoverflow.com/questions/18618522/unsafe-publication-concurrency-java – Mister Smith Oct 04 '13 at 13:03

4 Answers4

2

You misread the book. It explicitely says:

The problem here is not the Holder class itself, but that the Holder is not properly published.

So the above construct if fine. What's not fine is to improperly publish such an object to other threads. The book explains that in details.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • This is confusing . As in the quoted statemnt it says that casue of the problem is due to order of constructor calls "the Object constructor first writes the default values to all fields before subclass constructors run. *It is therefore Possible to see the default value for a field as a stale value*" And this is not in programmer's control , making filed n to be final could be a solution(a workaround) BUT still why it can fix the problem that really it cause i.e order of constructor calling and their intilisation – nish1013 Oct 04 '13 at 12:13
  • No, the cause of the problem is the improper publication of the object to other threads, allowing other threads to view the object in an inconsistent state. If you don't make the object available to other threads, or if you do it properly by publishing it properly (as described in the book), you'll never have the problem. volatile, synchronized, and other safe thread synchronization techniques are the solution. – JB Nizet Oct 04 '13 at 13:16
  • could you please provide an e.g please that this situation could occur – nish1013 Oct 04 '13 at 13:24
  • The example is in the book: *In fact, if the Holder in Listing 3.15 ispublished using the unsafe publication idiom in Listing 3.14, and athread other than the publishing thread were to call assertSanity, itcould throw AssertionError!* – JB Nizet Oct 04 '13 at 13:29
1

When creating a new object things happen sequentially. I don't know the precise order, but it's something like: allocate the space and initialize it to zeroes, then set the fields that get constant values, then set the fields that get calculated values, then run the constructor code. And, of course, it's got to initialize the subclasses in there somewhere.

So if you try to work with an object that is still being constructed, you can see odd, invalid values in the fields. This doesn't usually happen, but ways to do it:

  • Reference a field that doesn't yet have a value during an assignment to another field.

  • Reference a value in the constructor that doesn't get assigned till later in the constructor.

  • Reference a field in an object in a field in an object that was just read from an ObjectInputStream. (OIS often takes a long time to put values in objects it's read.)

  • Before Java 5, something like:

    public volatile MyClass  myObject;
    ...
    myObject = new MyClass( 10 );
    

    could make trouble because another thread could grab the reference to myObject before the MyClass constructor was finished and it would see bad values (zero instead of 10, in this case) inside the object. With Java 5, the JVM is not allowed to make myObject non-null until the constructor is finished.

  • And today you can still set myObject to this within the constructor and accomplish the same thing.

If you're clever, you can also get hold of Class fields before they've been initialized.

In your code example, (n != n) would be true if something changed the value between the two reads of n. I guess the point is n starts as zero, get's set to something else by the constructor, and assertSanity is called during the construction. In this case, n is not volatile so I don't think the assert will ever be triggered. Make it volatile and it will happen once every million times or so if you time everything precisely right. In real life this kind of problem happens just often enough to wreak havoc but rarely enough that you can't reproduce it.

RalphChapin
  • 3,108
  • 16
  • 18
  • "With Java 5, the JVM is not allowed to make myObject non-null until the constructor is finished." is this only valid when it is marked as volatile ? – nish1013 Oct 11 '13 at 07:57
  • 2
    @nish1013 __Yes!!!__ There's a sort of memory barrier here. When you write to a volatile _or_ leave a synchronized block _all your memory changes_ must, at that point, be visible to whatever thread next reads the volatile or synchs on the same monitor. (The "all memory changes" part was added for volatiles in Java 5.) (There are a couple of less common things that order memory changes also.) Normally, the changes have to _appear_ to occur in the order you wrote them only within a single thread, but can appear in _any_ order to a different thread. – RalphChapin Oct 11 '13 at 13:37
  • by "same monitor" you meant same object? – nish1013 Oct 11 '13 at 14:51
  • @nish1013 Yes. It's the object in the `synchronized` statment. – RalphChapin Oct 11 '13 at 17:07
0

I guess theoretically it is possible. It is similar to double checked locking problem.

public class Test {
    static Holder holder;

    static void test() {
        if (holder == null) {
            holder = new Holder(1);
        }
        holder.assertSanity();
    }
...

If test() is called by 2 threads, thread-2 might see the holder in a state when initialization is still in progress so n != n may happen to be true. Here is bytecode for n != n:

ALOAD 0
GETFIELD x/Holder.n : I
ALOAD 0
GETFIELD x/Holder.n : I
IF_ICMPEQ L1

as you can see JVM loads field n to operand stack twice. So it may happen that the first var gets value before init and the seccond after init

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • Is it really? I'm asking, not saying it isn't. I understand the threads may see different object or object which is not initialized. But I would expect the thread seeing single value only (default or set via contructor) and therefor `n != n` always return `false`. – Jan Zyka Oct 04 '13 at 11:47
  • But your code shows static instances and methods, unlike the code posted in the question. – Mister Smith Oct 04 '13 at 13:00
  • It still uses Holder instance and instance method holder.assertSanity() – Evgeniy Dorofeev Oct 04 '13 at 13:15
0

the comment:

the Object constructor first writes the default values to all fields before subclass constructors run

seems wrong. My prior experience is that the default values for a class are set before its constructor is run. that is a super class will see its init-ed variables set before its constructor runs and does things. This was root of bug a friend looked at where a base class was calling a method during construction that the super class implemented and set a reference that was defined with initialization to null in the super class. the item would be there until entry to the constructor at which time the init set it to null value.

references to the object are not available to another thread (assuming none generated in the constructor) until it completes construction and object reference is returned.

LhasaDad
  • 1,786
  • 1
  • 12
  • 19
  • Is this a guaranteed behavior ? any reference from JLS? – nish1013 Oct 04 '13 at 13:51
  • which section of my comment are you asking about the reference in the 2nd paragraph or the init behavior in first? (or did you want refs for both? – LhasaDad Oct 05 '13 at 14:18