Immutability and Thread Safety in Java  

by ne on 2021-09-29 under Java

There are 4 sections of this Article:

[This one] Immutability and Thread Safety Part1- Covers Immutability

Immutability and Thread Safety Part2- Covers Thread Safety

Immutability and Thread Safety Part3- More on Thread Safety and Concurrency

Immutability and Thread Safety Part4 - Covers How the above 2 are related, and some further concepts

 

Immutability means - a behavior of an object to not allow any modifications to its state, once the constructor for this object has finished execution.

In other words, An Immutable object  is a java object, which once created should not allow any modifications to its state (captured by class variables, instance variables). So if you get a reference to a newly created immutable object, then through the entire course of your application, you can be sure that the object's state will remain constant.

 

How to create an immutable object ?

Here's a simple Employee class (Mutable)


import java.util.Date;

public class Employee {
    int employeeId;
    String name;
    Date  dateOfJoinee;
    public Employee(){
        employeeId=1;
        name="Employee_1";
        dateOfJoinee=new Date();
    }
    public Employee(String name, int employeeId, Date dateOfJoinee){
        this.employeeId=employeeId;
        this.name=name;
        this.dateOfJoinee=dateOfJoinee;
    }

    public int getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getDateOfJoinee() {
        return dateOfJoinee;
    }

    public void setDateOfJoinee(Date dateOfJoinee) {
        this.dateOfJoinee = dateOfJoinee;
    }


    /**
     * other operations
     */
}

 

Now, the above class is clearly Mutable. We can instatiate an object and then modify it's state later, which can be unwanted or an undesired behavior.

And someOtherOperation() in some other class can modify the employee.


Employee employee=new Employee();
employee.setDateOfJoinee(new Date());
employee.setEmployeeId(111);
employee.setName("Naveen Soni");

someOtherMethod(employee); // can modify employee, since employee is Mutable

/**
 * expecting the Name to be "Naveen Soni"
 */
System.out.println("Employee created ! , name = "+employee.getName());
Some modification in that method

public void someOtherMethod(Employee employee){
        //  ...
        employee.setName("garbage");
        //  ...
}

 

To make it immutable, we should not allow anything to modify the state, after constructor.

So, remove code that modifies the data, after initialization.


public void setName(String name) {
    this.name = name;
}
public void setDateOfJoinee(Date dateOfJoinee) {
    this.dateOfJoinee = dateOfJoinee;
}

For any class's object, which you know is Mutable, don't return the object itself, return a copy

 

OR ELSE, the object's state can change, hence changing our object's state

For example, don't return dateOfJoining directly in the getter, return a copy(or clone object)


public Date getDateOfJoinee() {
    /**
     * create a copy of the Date object, or .clone(), if supported
     */
    return new Date(dateOfJoinee.getTime());
}

Now, we will have a class, without any setters, and non-impacting getters

But, why not declare the fields as private, strengthening encapsulation, and making sure, no body touches the fields without proper getter (except reflection)

Now, we have a decent class


public  class DecentEmployee {
    private  int employeeId;
    private  String name;
    private  Date  dateOfJoinee;

    public DecentEmployee(String name, int employeeId, Date dateOfJoinee){
        this.employeeId=employeeId;
        this.name=name;
        this.dateOfJoinee=dateOfJoinee;
    }

    public int getEmployeeId() {
        return employeeId;
    }

    public String getName() {
        return name;
    }

    public Date getDateOfJoinee() {
        /**
         * create a copy of the Date object, or .clone(), if supported
         */
        return new Date(dateOfJoinee.getTime());
    }

}

But is it immutable now ??

We didn't expose any setters, and fields are private, and are only initialized in the constructors
But, still, a new developer in the team comes in, and he wouldn't know that we don't want to modify the fields (even if it is documented, some people like to introduce bugs),
Then what.
He will go ahead and create new methods, which may modify the data.

In order to preserve the immutability, we should use a java keyword, final, which if applied to a variable, will allow only one value to be assigned to it, in its lifetime.

So, Ideally, in an immutable class, the class level variables should be declared as final.

But shouldn't we declare the class as final too, is this required ??

Declaring the class as final in java, means - no one can extend this class.

But is this any problem for us. Yes, since, final class can't be subclassed, That's important so that any code which is relying on its immutability can do so safely.

For instance, consider this  (IF WE are advertising our Employee class as Immutable class (without making the class as final)):


public class LazyEmployee extends Employee {
    /**
     * A mutable and non-thread-safe class
     */
}

 


public void aValidMethod(){
    LazyEmployee lazyEmployee=new LazyEmployee();
    //...

    //passes LazyEmployee (a mutable object)  to sensitiveOperation
    sensitiveOperation(lazyEmployee);
}
// ....
// ....
public void sensitiveOperation(Employee employee){
    /**
     * do some sensitive work, assuming employee is Immutable (and reasonably thread-safe)
     */
}

Now, here, sensitiveOperation is expecting the argument to be an immutable object (since Employee was advertised as Immutable),
but is it ? No, as we can see, the LazyEmployee was passed in, and that is not an immutable object - Which could be avoided, if only we declare our class as final.

Finally, the class will be



import java.util.Date;

public final class EmployeeFinal {
    private final int employeeId;
    private final String name;
    private final Date  dateOfJoinee;

    public EmployeeFinal(String name, int employeeId, Date dateOfJoinee){
        this.employeeId=employeeId;
        this.name=name;
        this.dateOfJoinee=dateOfJoinee;
    }

    public int getEmployeeId() {
        return employeeId;
    }

    public String getName() {
        return name;
    }

    public Date getDateOfJoinee() {
        /**
         * create a copy of the Date object
         */
        return new Date(dateOfJoinee.getTime());
    }

    /**
     * other operations
     */
}

 

Now, the above is a reasonably immutable class.

There are 4 sections of this Article: 
[This one] Immutability and Thread Safety Part1- Covers Immutability Immutability and Thread Safety Part2- Covers Thread Safety
Immutability and Thread Safety Part3- More on Thread Safety and Concurrency 
Immutability and Thread Safety Part4 - Covers How the above 2 are related, and some further concepts