Correct use of transient, volatile and final modifiers

transient

As we all know, as long as an object implements the Serializable interface, the object can be serialized in two ways:
- implement Serializable (automatic serialization)
- implement Externalizable (there is no automatic serialization, you need to specify so and so serialization yourself. See the following case for specific use)
  
As long as this class implements the serializable interface, all properties and methods of this class will be serialized automatically. In the actual development process, we often encounter such problems. Some attributes of this class need to be serialized, while other attributes do not need to be serialized. For example, if a user has some sensitive information (such as password, bank card number, etc.), for security reasons, Do not want to be transmitted in network operations (mainly involving serialization operations, and local serialization cache is also applicable). The variables corresponding to these information can be added with the transient keyword. In other words, the lifetime of this field is only stored in the caller's memory and will not be written to disk for persistence.
In short, the transient keyword of java provides us with convenience. You only need to implement the serializable interface and add the keyword transient before the attribute that does not need to be serialized. When serializing an object, this attribute will not be serialized to the specified destination.

Usage:

Implement Serializable usage:

package com.lyj.demo.pojo;

import lombok.Data;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @author Lingxi
 * @date 2021/4/13 15:28
 * Serializable And Transient testing
 */
@Data
public class User implements Serializable {

    /**
     * Once the variable is modified by transient, the variable will no longer be part of the object persistence, and the content of the variable cannot be accessed after serialization.
     * transient Keywords can only modify variables, not methods and classes. Note that local variables cannot be modified by the transient keyword. If the variable is a user-defined class variable, the class needs to implement the Serializable interface.
     * Variables modified by the transient keyword can no longer be serialized. A static variable cannot be serialized whether it is modified by the transient keyword or not.
     */

    private static final long serialVersionUID = -3757942349125027942L;

    private String name;

    private Integer age;

    /**
     * Using the transient keyword does not serialize a variable
     * Note that when reading, the order of reading data must be consistent with the order of storing data
     */
    private transient String password;

    /**
     * Variables modified by the transient keyword can no longer be serialized. A static variable cannot be serialized whether it is modified by the transient keyword or not
     * That is, modify the static variable value before deserialization, and its value will become modified
     */
    public static String desc;


    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("{");
        sb.append("\"name\":\"")
                .append(name).append('\"');
        sb.append(",\"age\":")
                .append(age);
        sb.append(",\"password\":\"")
                .append(password).append('\"');
        sb.append('}');
        return sb.toString();
    }

    public static void main(String[] args) {

        User user = new User();
        user.setAge(12);
        user.setName("aaa");
        user.setPassword("2141441341");
        System.out.println("read before Serializable:");
        // {"name":"aaa","age":12,"password":"2141441341"}
        System.out.println(user);

        try {
            // Write the user object into the file (when writing text, the class object must be serialized, otherwise an error will be reported)
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("./user.txt")));
            objectOutputStream.writeObject(user);
            objectOutputStream.flush();
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Read data from text after serialization");
        // Read the user from the text
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("./user.txt"));
            // Read data from stream
            User readUser = (User)objectInputStream.readObject();
            objectInputStream.close();
            // Output {"name":"aaa","age":12,"password":"null"}
            System.out.println(readUser);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }


    }
}



Operation results:

Implement Externalizable:

package com.lyj.demo.pojo;

import lombok.Data;

import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

/**
 * @author Lingxi
 * @date 2021/4/13 15:58
 * @description Externalizable Use of interfaces
 */
@Data
public class UserExternalizableTest implements Externalizable {


    /**
     * Java In, object serialization can be realized by implementing two interfaces,
     * Method 1: implement Serializable
     * Method 2: implement Externalizable
     *
     * If an Externalizable interface is implemented, nothing can be serialized automatically,
     * You need to manually specify the variables to be serialized in the writeExternal method,
     * This has nothing to do with whether it is modified by transient.
     */

    private String name;

    private Integer age;

    private transient String password;

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(password);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        password = (String) in.readObject();
    }

    public static void main(String[] args) {
        UserExternalizableTest user = new UserExternalizableTest();
        user.setAge(12);
        user.setName("aaa");
        user.setPassword("2141441341");
        System.out.println("read before Serializable:");
        // UserExternalizableTest(name=aaa, age=12, password=2141441341)
        System.out.println(user);
        try {
            // Write the user object into the file (when writing text, the class object must be serialized, otherwise an error will be reported)
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("./user.txt")));
            objectOutputStream.writeObject(user);
            objectOutputStream.flush();
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Read data from text after serialization");
        // Read the user from the text
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("./user.txt"));
            // Read data from stream
            UserExternalizableTest readUser = (UserExternalizableTest)objectInputStream.readObject();
            objectInputStream.close();
            // UserExternalizableTest(name=null, age=null, password=2141441341)
            System.out.println(readUser);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

Operation results:

transient summary

  • Once the variable is modified by transient, the variable will no longer be a part of object persistence, and the content of the variable cannot be accessed after serialization.
  • The transient keyword can only modify variables, not methods and classes. Note that local variables cannot be modified by the transient keyword. If the variable is a user-defined class variable, the class needs to implement the Serializable interface.
  • Variables modified by the transient keyword can no longer be serialized. A static variable cannot be serialized whether it is modified by the transient keyword or not.

volatile

The member variable modified by volatile forces the value of the member variable to be re read from main memory every time the thread accesses it. Moreover, when the Cheng Yan variable changes, the thread is forced to write the change value back to main memory. In this way, at any time, two different threads always see the same value of a member variable.
The java language specification points out that in order to obtain the best speed, the thread is allowed to save the private copy of the shared member variable, and the original value of the shared member variable is compared only when the thread enters or leaves the synchronous code block.
In this way, when multiple threads interact with an object at the same time, we must pay attention to making the threads get the changes of shared member variables in time.
The volatile keyword is to prompt the VM that the private copy of this member variable cannot be saved, but should interact directly with the shared member variable.
Usage suggestion: use volatile on member variables accessed by two or more threads. It is not necessary to use when the variable to be accessed is already in the synchronized code block or is a constant.
Since the use of volatile masks the necessary code optimization in VM, it is inefficient. Therefore, this keyword must be used when necessary.

final

The instance domain can be defined as final. Such a domain must be initialized when building objects. In other words, you must ensure that the value of this field is set after each constructor is executed, and it cannot be modified in subsequent operations.

The final modifier is mostly applied to the field of basic data type or the field of immutable class (if the methods in the class will not change their objects, this kind is immutable class. For example, String class is an immutable class). For mutable classes, using the final modifier can cause confusion for readers. For example,

private final Date hiredate;

It only means that the object reference stored in the hiredate variable cannot be changed after the object is constructed, but it does not mean that the hiredate object is a constant. Any method can call the setTime changer on the object referenced by hiredate.

Keywords: volatile final

Added by PowersWithin on Tue, 08 Mar 2022 02:05:46 +0200