Concurrent Programming Fundamentals — Sharing Objects (Part 3)

Gowthamy Vaseekaran
4 min readMar 11, 2021

In this blog we are going to discuss about “Immutability”.

The other end-run around the need to synchronize is to use immutable objects. Almost all the atomicity and visibility concepts in previous blogs (blog 1 & blog 2).

Immutability

  • An immutable object is one whose state cannot be changed after it is created.
  • Immutable objects are inherently thread-safe.
  • Their invariants are established by the constructor, and if their state cannot be changed, these invariants always hold.

Immutable objects are very simple. They can only be in one state, which is carefully controlled by the constructor. One of the most difficult elements of program design is reasoning about the possible states of complex objects.

Immutable objects are also safer. Passing a mutable object to un-trusted code,
or otherwise publishing it where un-trusted code could find it, is a really dangerous action.The un-trusted code might modify its state, or, worse, retain a reference to it and modify its state later from another thread.

On the other hand, immutable objects cannot be subverted in this manner by malicious or buggy code, so they are safe to share and publish freely without the need to make defensive copies.

An object is immutable if:

  • Its state cannot be modified after construction
  • It is properly constructed (the this reference does not escape during
    construction).

Okay let see how we can implement immutability in java.

Creating an Immutable Object

To create an immutable object you need to follow some simple rules:

  • Don’t add any setter method
  • Declare all fields final and private
  • If a field is a mutable object create defensive copies of it for getter methods.
  • If a mutable object passed to the constructor must be assigned to a field create a defensive copy of it.
  • Don’t allow sub-classes to override methods.

Now lets discover point by point the reasons of the five rules explained before.

Don’t add any setter method

If you are building an immutable object its internal state will never change. Task of a setter method is to change the internal value of a field, so you can’t add it.

Declare all fields final and private

A private field is not visible from outside the class so no manual changes can’t be applied to it.

Declaring a field final will guarantee that if it references a primitive value the value will never change, if it reference an object the reference can’t be changed. This is not enough to ensure that an object with only private final fields is not mutable. Here is an example showing an object with a private final field and an example on how to mutate its internal state:

public class DateContainer {
private final Date date;
public DateContainer() {
this.date = new Date();
}
public Date getDate() {
return date;
}
}
.... DateContainer dateContainer = new DateContainer();
System.out.println(dateContainer.getDate());
dateContainer.getDate().setTime(dateContainer.getDate().getTime() + 1000);
System.out.println(dateContainer.getDate());

If a field is a mutable object create defensive copies of it for getter methods

We have seen before that defining a field final and private is not enough because it is possible to change its internal state. To solve this problem we need to create a defensive copy of that field and return that field every time it is requested.

Here is the previous class with that modification:

public class DateContainer {
private final Date date;
public DateContainer() {
this.date = new Date();
}
public Date getDate() {
return new Date(date.getTime());
}
}
.... DateContainer dateContainer = new DateContainer();
System.out.println(dateContainer.getDate());
dateContainer.getDate().setTime(dateContainer.getDate().getTime() + 1000);
System.out.println(dateContainer.getDate());

If a mutable object passed to the constructor must be assigned to a field create a defensive copy of it

The same problem happens if you hold a reference passed to the constructor because it is possible to change it.

Here we show a modified example of DateContainer that accept a Date for the constructor and we will see how it is possible to change its internal state:

public class DateContainer {
private final Date date;
public DateContainer(Date date) {
this.date = date;
}
public Date getDate() {
return new Date(date.getTime());
}
}
.... Date date = new Date();
DateContainer dateContainer = new DateContainer(date);
System.out.println(dateContainer.getDate());
date.setTime(date.getTime() + 1000);
System.out.println(dateContainer.getDate());

So holding a reference to an object passed to the constructor can create mutable objects. To solve this problem it is necessary to create a defensive copy of the parameter if they are mutable objects:

public class DateContainer {
private final Date date;
public DateContainer(Date date) {
this.date = new Date(date.getTime());
}
public Date getDate() {
return new Date(date.getTime());
}
}
.... Date date = new Date();
DateContainer dateContainer = new DateContainer(date);
System.out.println(dateContainer.getDate());
date.setTime(date.getTime() + 1000);
System.out.println(dateContainer.getDate());

Note that if a field is a reference to an immutable object is not necessary to create defensive copies of it in the constructor and in the getter methods it is enough to define the field as final and private.

As an example of common immutable objects there are String, all primitive wrappers (Integer, Long, Double, Byte….), BigDecimal, BigInteger.

Don’t allow sub-classes to override methods

If a subclass override a method it can return the original value of a mutable field instead of a defensive copy of it.

To solve this problem it is possible to do one of the following:

  • Declare the immutable class as final so it can’t be extended
  • Declare all methods of the immutable class final so they can’t be overriden.
  • Create a private constructor and a factory to create instances of the immutable class because a class with private constructors can’t be extended.

If you follow those simple rules you can freely share your immutable objects between threads because they are thread safe!

Happy Learning !!!

--

--

Gowthamy Vaseekaran

Senior Software Engineer @ hSenid Mobile | Former Software Engineering Intern @ WSO2 | Software Engineering Undergraduate @ IIT