I recently started learning C# and went straight for the memory model. C# and Java have similar (though perhaps not identical) thread safety guarantees regarding reads and writes of volatile
fields. But unlike writes to final
fields in Java, writes to readonly
fields in C# do not provide any specific thread safety guarantee. Thinking about how thread safety works in C# led me to doubt whether there is any real advantage to final
fields behaving the way they do in Java.
I learned about the supposed importance of final
three years ago. I asked this question and got a detailed answer that I accepted. But now I think it's wrong, or at least irrelevant. I still think fields should be final
whenever possible, just not for the reasons commonly believed.
The value of a final
field is guaranteed to be visible to any other thread after the constructor returns. But the reference to the object itself must be published in a thread safe manner. If the reference is published safely, then the visibility guarantee of final
becomes redundant.
I considered the possibility that it has something to do with public static
fields. But logically, a class loader must synchronize the initialization of a class. Synchronization makes the thread safety of final
redundant.
So I'm putting forth the heretical idea that the only real value of final
is to make immutability self-documenting and self-enforcing. In practice, private non-final fields (and in particular, array elements) are perfectly thread safe as long as they are not modified after the constructor returns.
Am I wrong?
Edit: Paraphrasing section 3.5 of Java Concurrency in Practice,
Two things can go wrong with improperly published objects. Other threads could see a stale value for the reference, and thus see a null reference or other older value even though a value has been set. But far worse, other threads could see an up-to-date value for the reference, but stale values for the state of the object.
I understand how final
fields solve the second problem, but not the first problem. The highest voted answer so far argues that the first problem is not a problem.
Edit 2: This question arises from a confusion of terminology.
Like the asker of a similar question, I've always understood the term "safe publication" to mean that both an object's internal state and the reference to the object itself are guaranteed visible to other threads. In favor of this definition, Effective Java cites Goetz06, 3.5.3 in defining "safe publication" as (emphasis added)
Transferring such an object reference from one thread to others
Also in favor of this definition, note that the section of Java Concurrency in Practice paraphrased above refers to potentially stale references as being "improperly published."
Whatever you call it, I didn't think that unsafely publishing a reference to an immutable object could ever be useful. But according to this answer, it can. (The example given there is a primitive value, but the same principle could apply to reference values.)
But the reference to the object itself must be published in a thread safe manner. If the reference is published safely, then the visibility guarantee of
final
becomes redundant.
The first sentence is wrong; the second is therefore irrelevant. final
may be redundant in the presence of other safe publication techniques, like synchronization or volatile
. But the point of immutable objects is that they're inherently thread-safe, meaning they'll be seen in a consistent state regardless of how the reference is published. So you don't need those other techniques in the first place, at least as far as safe publication is concerned.
EDIT: OP correctly points out that there's some ambiguity around the term "safe publication". In this context I'm referring to consistency of the object's internal state. The issue of visibility as it affects the reference is, in my opinion, a valid but separate concern.