Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe publication of immutable objects in Java

I want to understand if volatile is needed to publish immutable objects.

For example, assuming we have an immutable object A:

// class A is immutable
class A {
  final int field1;
  final int field2;

  public A(int f1, int f2) {
    field1 = f1;
    field2 = f2;
  }
}

Then we have a class B that is accessed from different threads. It holds a reference to an object of class A:

// class B publishes object of class A through a public filed
class B {
  private /* volatile? */ A toShare;

  // this getter might be called from different threads
  public A getA(){
    return toShare;
  }

  // this might be called from different threads
  public void setA(num1, num2) {
    toShare = new A(num1, num2);
  }
}

From my reading it seems immutable objects can be safely published through any means, so does that mean we don't need to declare toShare as volatile to ensure its memory visibility?

like image 623
aha Avatar asked Apr 09 '16 23:04

aha


People also ask

Is immutable object thread-safe?

To put it simply, a class instance is immutable when its internal state can't be modified after it has been constructed. A MessageService object is effectively immutable since its state can't change after its construction. So, it's thread-safe.

What objects are immutable in Java?

Immutable class in java means that once an object is created, we cannot change its content. In Java, all the wrapper classes (like Integer, Boolean, Byte, Short) and String class is immutable.

Where are immutable objects stored in Java?

Like strings contained in the pool are still stored in the heap memory, objects of your class are still stored in the heap memory when being referenced by whatever data structure used for the pool is referencing them.


1 Answers

No, you are not guaranteed that you'll be seeing all updates to the toShare field of your shared data. This is because your shared data does not use any synchronization constructs that guarantee its visibility or the visibility of references reachable through it across threads. This makes it open game for numerous optimizations on the compiler and hardware level.

You can safely change your toShare field to reference a String (which is also immutable for all your purposes) and you'll probably (and correctly) feel more uneasy about its update visibility.

Here you can see a rudimentary example I've created that can show how updates are lost without any additional measures to publish changes to the reference of an immutable object. I've ran it using the -server JVM flag on JDK 8u65 and Intel® Core™ i5-2557M, disregarding the possibly thrown NullPointerException and saw the following results:

  • Without safe being volatile, the second thread doesn't terminate because it doesn't see many of the changes made by the first thread

Console output:

[T1] Shared data visible here is 2147483647
  • When safe is changed to be volatile, the second thread terminates alongside the first thread

Console output:

[T1] Shared data visible here is 2147483647
[T2] Last read value here is 2147483646
[T2] Shared data visible here is 2147483647

P.S. And a question to you - what happens if sharedData (and not safe) is made volatile? What could happen according to the JMM?

like image 191
Dimitar Dimitrov Avatar answered Sep 28 '22 03:09

Dimitar Dimitrov