Difference between volatile and transient in Java

1. Introduction

In Java, volatile and transient are two keywords that serve distinct purposes. 

The volatile keyword indicates that a variable's value will be modified by different threads. 

The transient indicates that a field should not be serialized—that is, not saved as part of the object's state.

2. Key Points

1. volatile is used to make sure that the value of a variable is always read from the main memory and not from the thread's cache.

2. transient is used to prevent fields from being serialized during the serialization process.

3. Changes to a volatile variable are always visible to other threads.

4. transient variables are reset to the default value when an object is deserialized.

3. Differences

volatile transient
Ensures the variable's value is read from and written to the main memory. Excludes a variable from the serialization process.
Ensures that changes made in one thread are immediately visible to other threads. Prevents a variable from being serialized with the object.
It does not store the value of the variable in the thread's cache; all reads and writes are directly from and to the main memory. The variable is skipped by the serialization mechanism, making it not part of the object's serialized state.
Does not prevent a variable from being serialized. Specifically used to exclude variables from serialization.
Useful in concurrent programming to make class thread-safe by ensuring the visibility of variables across threads. Useful when you want to avoid sensitive or unnecessary data being saved or transmitted.

4. Example


import java.io.*;

// Example of volatile
class SharedObject {
    // The value of this variable will be read from the main memory every time.
    volatile int sharedCounter = 0;

    void increment() {
        sharedCounter++;
    }
}

// Example of transient
class User implements Serializable {
    String name;
    transient String password; // This field will not be serialized

    User(String name, String password) {
        this.name = name;
        this.password = password;
    }
}

public class Main {
    public static void main(String[] args) {
        SharedObject sharedObject = new SharedObject();
        sharedObject.increment();

        User user = new User("JohnDoe", "s3cr3t");

        // Serialization
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("userInfo.ser"))) {
            oos.writeObject(user);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Deserialization
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("userInfo.ser"))) {
            User deserializedUser = (User) ois.readObject();
            System.out.println("Name after deserialization: " + deserializedUser.name);
            System.out.println("Password after deserialization: " + deserializedUser.password);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Output:

Name after deserialization: JohnDoe
Password after deserialization: null

Explanation:

1. The sharedCounter variable is marked as volatile, which means any changes made to its value are reflected across threads.

2. The User class has a transient field password, which is not serialized. Upon deserialization, the password field is null because transient fields are not saved.

3. The main method demonstrates the serialization and deserialization process. The name is serialized and deserialized with its value intact, whereas password is not, due to it being marked as transient.

5. When to use?

- Use volatile when you need to ensure that multiple threads see the most up-to-date value for a variable.

- Use transient when you have fields that should not be part of the serialized state, such as sensitive information or fields that only make sense in the

Comments