What is the purpose of Transient and Volatile in Java?

Asked

Viewed 17,504 times

28

Sometimes when I declare my attributes I notice the transient and the volatile. I have the following doubts

  • The transient and volatile are access modifiers?
  • What is the purpose of using them?

Example:

transient String a;
volatile String b;
  • 4

    Is there this in java? huahuahua has never seen it before. + 1

  • There is, rs @Diegof

3 answers

40


They are not access modifiers, but modify how the Java Virtual Machine handles attributes at runtime.

Transient attributes

A transient attribute means that it will not be serialized or deserialized along with the other attributes of a given object.

Serialization is the process in which the attributes of an object (state) are converted, one by one, into a sequence of bytes. Deserialization is the reverse process, where bytes are read and a new object is built.

The most common applications are:

  • Transmission of objects over the network. Often used in Apis such as:
    • JNDI: access to an object directory
    • RMI: remote method invocation
    • Servlets: distribution of objects in the session between nodes of a cluster
  • Save objects to files or databases. This is usually an approach ad hoc to save settings or state in an "easy"

You explicitly define that you do not want to serialize a particular attribute with transient basically in the following cases:

  • You want to serialize the class, but an attribute of a certain type (class) is not serializable, so the process would fail.
  • The attribute value is some kind of cache and you don’t need it, so it saves memory and processing.
  • The attribute represents some local entity and it makes no sense to transmit it, for example a connection to the database (Connection) or any reference to a resource that needs to be opened and closed.

It is also important to mention that this attribute has no effect if you overwrite the methods writeObject and readObject, enabling, respectively, the serialization and manual deserialization of objects.

Volatile attributes

Work with several threads It causes a lot more headaches than you can imagine. This is because often multiple threads need to access and modify shared objects.

Imagine the following scenario:

long i = 0;
void thread1() {
  ...
  i++;
  ...
}
void thread2() {
  ...
  if (i == 1) {
    fazAlgo();
  }
  ...
}

In the example, the two threads access the same variable. Assuming the reading of the thread2 occurs, in a time sequence, exactly after the increment of the thread1, you think there might be some competition problem, considering the increment looks like an atomic operation?

A naive analysis would say that everything is fine with the threads because the two perform atomic writing and reading operations, so fazAlgo would run smoothly.

Wrong.

Each thread can is running on a different processor. Each processor can have a cache own. Variables are read and saved first in the local cache before going to the main memory. Then, it is possible that the second thread read the old value of the variable.

The problematic scenario would occur like this:

  1. T1 reads the value of i = 0 from the main memory and increments; the new value i = 1 is stored in the local cache, but not in the main memory.
  2. T2 reads the value of i = 0 of the main memory and does not enter the if.

Worse than that, 64-bit variables like long and double may have its written in memory divided by the JVM into two 32-bit cycles, which could lead to a completely corrupted reading of its values.

Such scenarios are relatively rare, but extremely difficult to identify in complex software, causing that kind of intermittent and occasional problem that ends up being swept under the carpet.

The solution, in this case, is simple:

volatile long i = 0;

A volatile attribute is guaranteed that the updated value will always be available to others threads, being recorded in the main memory as soon as updated, atomic form.

This means that whenever the value is modified in a processor, a flush to the main memory, therefore the others threads will always see the most updated value and not a possible outdated value.

Of course this is not free. Do the flush from cache to main memory penalizes performance, after all there is a reason for hardware manufacturers to place caches on processors. It is much faster to access a register or primary cache than to access RAM.

An alternative solution would be to use synchronization methods as a block synchronized or atomic variables such as AtomicLong, which may be necessary when there is concurrent modification, but which are slower.

In the case of competing writing, as well remembered by Rafael in the other answer, a variable volatile could still incur running condition as the two threads can read the same value as the main memory, and the final value would depend on which of the threads would he write last.

Interestingly, the class AtomicLong uses volatile:

private volatile long value;

What is the difference then? It occurs that the atomic classes use the technique known as compare and swap, that is, the variable update operation is conditioned to the old value. For example, each thread sends an instruction similar to "update the value 1 to 2". The processor then ensures that the variable will only be updated to 2 if its value is 1, otherwise the operation fails. Let’s say the value was now 3 and the operation failed. The thread now tries again with "update the value 3 to 2" and so on until it succeeds. This technique ensures that the safe update of the value in memory.

  • 1

    Excellent explanation, thank you.

  • 2

    Considering the new answer, I believe this one will require some sort of rectification.

  • @Piovezan Thanks for the touch. I stepped on the ball at the time of example, it had to be modification and reading and not two same modifications. I think at the time I tried to make it very simple and it ended up being incorrect. As for the atomic increment operation, it was not my intention to confirm this in any way. It is implied in the answer that this is something that people assume, but reading the step by step execution I made it very clear that the operation is divided into read and update. Updated response!

5

Regarding the Transient is what everyone said above, I have nothing to add, however, it is necessary to keep in mind that a volatile attribute has the function of not storing caches, which ends up helping the problem of the situation below:

volatile int i = 0;                                                              
void thread1() {                                                                 
  i++;                                                                 
}                                                                 
void thread2() {                                                                 
  i++;                                                                 
} 

However, this solution does not eliminate the race condition problem, because if both threads try to increase the variable at the same time, the volatile does not prevent this value from remaining wrong. For this, it is necessary to synchronize this stretch of the increment as a critical zone.

A more appropriate use for this variable would be something like:

public class Foo extends Thread {
    private volatile boolean close = false;
    public void run() {
        while(!close) {
            // do work
        }
    }
    public void close() {
        close = true;
        // interrupt here if needed
    }
}

4

  • 2

    Could you explain it better? Anyone who doesn’t know English(like me) won’t understand much about the definitions.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.