-1

Consider the following code:

public class Resource {
    public int val;
    public Resource() {
        val = 3;
    }
}

public class UnsafePublication {
    public static Resource resource;

    public static void initialize() {
        resource = new Resource();
    }
}

In Thread1

UnsafePublication.initialize();

In Thread2

while (true) {
    if (UnsafePublication.resource != null) {
        System.out.println(UnsafePublication.resource.val);
        break;
    }
}

We know that the unsafe publication may lead to Thread2 printing 0 instead of 3.

After going through many reference materials, I concluded two explanations:

  1. Assume the assignment resource = new Resource(); does write through, so Thread2 will find UnsafePublication.resource is not null. But the assignment val = 3; in the constructor of Resource does not write through, so the val will be the default 0 value.
  2. There is a reorder when assigning new Resource() to resource. To be more specific:

    1. allocate the memory for a Resource object
    2. call Resource' s constructor to initialize the object
    3. assign the object to the field "resource"

    is reordered to:

    1. allocate the memory for a Resource object
    2. assign the object to the field "resource"
    3. call Resource' s constructor to initialize the object.

    So if Thread1 just finishes the step2 in the reordered version, and Thread2 is swapped in, then Thread2 will find UnsafePublication.resource.val is the default 0 value.

So here is my question: Are both of the explanations correct and possible? And in the real world, are these two factors may even mixed to make the situation more complicated?

folkboat
  • 167
  • 1
  • 7
  • 2
    It wouldn't print `0`as `resource`would be `null` – jhamon May 14 '20 at 08:16
  • @jhamon Yeah! Since the `resource` is not volatile, the update in Thread1 is not guaranteed to be visible to Thread2, but it is possible. (If I didn't understand some reference materials in a wrong way...) In the explanation1, I assume the `resource ` is indeed written through and visible to other threads. – folkboat May 14 '20 at 08:25
  • There are no threads in your example code, so it does not behave as you claim. – user207421 May 14 '20 at 08:26
  • @user207421 In the bottom of the code block, I commet the actions of two threads... – folkboat May 14 '20 at 08:28

1 Answers1

2

There are three possibilities here.

  • Thread2 may view resource as null.
  • Thread2 may view a reference to a partially constructed instance (i.e. memory is allocated on the heap, but the variables are not yet initialized), so the value of val variable might be zero.
  • Thread2 may observe a fully constructed instance and the latest value of the variable, which is 3.

In fact, you can't predict the behavior of the program since there's no any happens before link established between the write and subsequent read operations. So, all the combinations of events are possible.

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
  • Thanks! Is *partially constructed* means the situation I talked about in explanation2? Then how about explanation1? Will the instance be fully constructed in Thread1 but the `val` in it is still not visible to Thread2? – folkboat May 14 '20 at 08:40
  • Both of the explanations coincide with each other. – Ravindra Ranwala May 14 '20 at 08:47
  • I'm not sure but on `resource = new Resource();`, don't the constructor need to fully execute before assignig "resource"? Thus making the second point not possible? – jhamon May 14 '20 at 08:58
  • @jhamon Actually the `resource = new Resource() ` statement contains three steps. Firstly, allocate the memory on heap for the object. This is creation. Secondly, call constructor for that object. This is initialization. Thirdly, assign the address of the object to `resource`. The second step and third step can be swapped for optimisation, which I found [here](https://stackoverflow.com/a/45858064/9107303) – folkboat May 14 '20 at 09:08
  • What you say may be correct from the perspective of the current thread, due to program order rule. But from the perspective of a different thread is it no longer valid. @jhamon – Ravindra Ranwala May 14 '20 at 10:05
  • 1
    Interesting. I found a related post [here](https://stackoverflow.com/questions/681881/when-does-a-java-object-become-non-null-during-construction) – jhamon May 14 '20 at 10:33