Many questions/answers have indicated that if a class object has a final
field and no reference to it is exposed to any other thread during construction, then all threads are guaranteed to see the value written to the field once the constructor completes. They have also indicated that storing into a final
field a reference to a mutable object which has never been accessed by outside threads will ensure that all mutations which have been made to the object prior to the store will be visible on all threads which access the object via the field. Unfortunately, neither guarantee applies to writes of non-final
fields.
A question I do not see answered, however, is this: If the semantics of a class are such that a field cannot be final
, but one wishes to ensure the "publication" of the field and the object identified thereby, what is the most efficient way of doing that? As an example, consider
class ShareableDataHolder<T>
{
Object data; // Always identifies either a T or a SharedDataHolder<T>
}
private class SharedDataHolder<T> extends ShareableDataHolder<T>
{
Object data; // Always identifies either a T or a lower-numbered SharedDataHolder<T>
final long seq; // Immutable; necessarily unique
}
The intention would be that data
will initially identify a data object directly, but that it could legitimately at any time be changed to identify a SharedDataHolder<T>
which directly or indirectly encapsulates an equivalent data object. Assume all code is written to work correctly (though not necessarily optimally-efficiently) if any read of data
may arbitrarily return any value that was ever written to data
, but may fail if it reads null
.
Declaring volatile Object data
would be semantically correct, but would likely impose extra costs on every subsequent access to the field. Entering a dummy lock after initially setting the field would work, but would be needlessly slow. Having a dummy final
field, which the object sets to identify itself would seem like it should work; although technically I think it might require that all accesses to the other field be done through the other field, I can't see any realistic scenario where that would matter. In any case, having a dummy field whose purpose is only to provide the appropriate synchronization via its existence would seem wasteful.
Is there any clean way to inform the compiler that a particular write to data
within the constructor should have a happens-before relationship with regard to any reads of that field which occur after the constructor returns (as would be the case if the field were final
), without having to pay the costs associated with volatile
, locks, etc.? Alternatively, if a thread were to read data
and find it null, could it somehow repeat the read in such a fashion as to establish a "happens after" with regard to the write of data
[recognizing that such a request might be slow, but shouldn't need to happen very often]?
PS--If happens-before relationships are non-transitive, would a proper happens-before relationship exist in the following scenario?
- Thread 1 writes to a non-final field
dat
in some objectFred
and stores a reference to it into to a final fieldGeorge
. - Thread 2 copies the reference from
George
into a non-final fieldLarry
. - Thread 3 reads
Larry.dat
.
From what I can tell, a happens-before relationship exists between the write of Fred's field dat
and a read of George
. Would a happens-before relationship exist between the the write of Fred's dat
and a read of Larry
that returns a reference to Fred that was copied from a final
reference to Fred
? If not, is there any "safe" way to copy a reference contained in a final
field to a non-final field that would be accessible via other threads?
PPS--If an object and its constituents are never accessed outside their creation thread until the main constructor finishes, and the last step of the main constructor is to stores within the main object a final
reference to itself, is there any "plausible" implementation/scenario where another thread could see a partially-constructed object, whether or not anything actually uses that final
reference?