Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top