Java Thread Safety of Initialized Objects

Viewed 1656

Consider the following class:

public class MyClass
{
    private MyObject obj;

    public MyClass()
    {
        obj = new MyObject();
    }

    public void methodCalledByOtherThreads()
    {
        obj.doStuff();
    }
}

Since obj was created on one thread and accessed from another, could obj be null when methodCalledByOtherThread is called? If so, would declaring obj as volatile be the best way to fix this issue? Would declaring obj as final make any difference?

Edit: For clarity, I think my main question is: Can other threads see that obj has been initialized by some main thread or could obj be stale (null)?

6 Answers

The originally picked answer by @Sotirios Delimanolis is wrong. @ZhongYu 's answer is correct.

There is the visibility issue of the concern here. So if MyClass is published unsafely, anything could happen.

Someone in the comment asked for evidence - one can check Listing 3.15 in the book Java Concurrency in Practice:

public class Holder { 
    private int n;
    
    // Initialize in thread A
    public Holder(int n) { this.n = n; }
    
    // Called in thread B
    public void assertSanity() { 
        if (n != n) throw new AssertionError("This statement is false."); 
    }

}

Someone comes up an example to verify this piece of code:

coding a proof for potential concurrency issue

As to the specific example of this post:

public class MyClass{
    private MyObject obj;
    
    // Initialize in thread A
    public MyClass(){
        obj = new MyObject();
    }
    
    // Called in thread B
    public void methodCalledByOtherThreads(){
        obj.doStuff();
    }
}

If MyClass is initialized in Thread A, there is no guarantee that thread B will see this initialization (because the change might stay in the cache of the CPU that Thread A runs on and has not propagated into main memory).

Just as @ZhongYu has pointed out, because the write and read happens at 2 independent threads, so there is no happens-before(write, read) relation.

To fix this, as the original author has mentioned, we can declare private MyObject obj as volatile, which will ensure that the reference itself will be visible to other threads in timely manner (https://www.logicbig.com/tutorials/core-java-tutorial/java-multi-threading/volatile-ref-object.html) .

Related