abksrv
abksrv

Reputation: 1405

Difference in memory model semantics between final and volatile fields in Java

From Java Concurrency In Practice:

When a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread.(p25)

And,

Final fields can't be modified(although the objects they refer to can be modified if they are mutable), but they also have special semantics under the Java Memory Model. It is the use of final fields that makes possible the guarantee of initialization safety(see Section 3.5.2) that lets immutable objects be freely accessed and shared without synchronization.(p32)

Reciting an unsafe publication:

public class Holder {
      private int n;
      public Holder(int n) { this.n = n; }
      public void assertSanity() {
         if (n != n) // might be true for other threads.
     }
}

The value of n, surprisingly might be seen stale by other threads. But final modifier would do the trick. Similar to volatile, isn't it? Are final fields intrinsically volatile? (a possible explanation why final volatile is not allowed)

Upvotes: 1

Views: 346

Answers (3)

Dimitar Dimitrov
Dimitar Dimitrov

Reputation: 16367

No, final fields are not intrinsically volatile.

If they were, that would have been unnecessarily expensive, because in most cases you need to put a StoreLoad barrier after a volatile write.

This can be avoided for final fields, because you have an additional constraint that can help you - you know that final fields must be initialized by the time the corresponding class or instance object is fully initialized.

The specification can be somewhat hard to read (take a look at section 17.5 of the JLS), but keep in mind that, like the notorious JMM Causality section, the main point was to formally describe what would be the intuitive behavior for most people.

As for implementation, it usually requires 2 things:

  1. Ensuring that final field stores, including stores down the chain if the field is a reference, cannot be reordered with stores outside of the constructor. This is often a no-op, even if you inline your constructor, if the underlying hardware architecture has a strong memory model (like x86).

  2. Ensuring that the first final field load in a given thread cannot be reordered with the first load in that same thread of the corresponding reference to which the field belongs to. This is almost always a no-op, as all compilers and most hardware architectures honor load dependencies.

In the end, the much less expensive on most architectures LoadStore and StoreStore barriers should be enough for implementing final fields.

===

You can read more about how final fields should be implemented under the covers in:

===

P.S. Unsafe publication is dangerous even in the presence of final fields. See here for some caveats.

Upvotes: 3

Cootri
Cootri

Reputation: 3836

Is it a possible reason private volatile is not allowed?

private volatile is allowed.

Do you mean final volatile? Yes, these modifiers are incompatible by their nature - final var, which value/reference cannot be changed, do not need additional volatile goodies (and associated overhead) because mutation of final field is impossible and reads across multiple threads are consistent

But JMM does provide initialisation volatile-style consistancy for final fields. AFAIK it was implemented in JSR 133 (included in Java SE 5.0). Before this JSR init reads could be inconsistent during data race (and return null or some intermediate value for example)

PS: I've found classic article which mentions your problem. Highly recommend it (and the second part)

Upvotes: 1

volatile only has relevance to modifications of the variable itself, not the object it refers to. It makes no sense to have a final volatile field because final fields cannot be modified. Just declare the field final and it should be fine.

Upvotes: 0

Related Questions