Reputation: 2254
Many times I saw constructions like this one:
class OneTimeWriter {
volatile Object o;
void synchronized set(Object o) {
if(this.o == null) this.o = o;
}
Object get() {
return this.o;
}
}
We have read/write membars at the begining/end of synchronized
itself. So, can we remove volatile
from o, since synchronized
has release/acquire semantics itself?
Upvotes: 1
Views: 355
Reputation: 43391
Synchronization isn't absolute; it's always relative to another action. In the case of a synchronized
block, the synchronization is between the closing of one synchronized
block and the opening of a subsequent one on the same object.
Since your get
method doesn't use synchronized
, there is no happens-before relationship established between it and the set
method. The getting thread could read a partially-set object put in by the setter, due to reorderings. For instance, if you put in ("Foo", 123)
, the getting thread could read that that same object as having state (null, 123)
: the 123
state is there, but the "Foo"
state hasn't yet been written (or flushed to this core's memory, etc).
Besides the synchronized
block, another form of synchronization happens between the writing of a volatile
field and the subsequent reading of that same field. That — and only that — is what provides the happens-before relationship you need in this case. The synchronized
block in the setter only makes sure that this.o
isn't set twice, nothing more.
Upvotes: 1
Reputation: 77177
Not unless get
is also synchronized
; otherwise, there's no happens-before relationship between the setter putting something non-null
into the field and the get
call.
Upvotes: 1