Reputation: 1405
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
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:
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).
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
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
Reputation: 142
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