Reputation: 12366
Java Concurrency in Practice has the following example:
@ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache = new OneValueCache(null, null);
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i);
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors);
}
encodeIntoResponse(resp, factors);
}
}
}
The OneValueCache
is immutable.
From what I understand using volatile
ensures that all threads see up-to-date reference stored in the cache
variable.
At the same time it says that
Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them.
For me it says that we actually don't need that volatile
above that we used for synchronization.
JLS
also has the following example:
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
They don't use volatile
for field f
. Doesn't it mean that other threads can see f
as null
and never see the created instance?
Could someone explain?
Upvotes: 2
Views: 357
Reputation: 692
From what I understand using
volatile
ensures that all threads see up-to-date reference stored in the cache variable.
That's right, but this concept applies to the variable while the statement quoted from JCiP
Immutable objects can be used safely by any thread without additional synchronization, even when synchronization is not used to publish them.
does not apply to a variable but to the object itself. It means that a thread will always see a fully constructed object without any data races independent on how it is published because as JCiP states
Immutable objects can be published through any mechanism.
Now in regard to your second example:
Doesn't it mean that other threads can see f as null and never see the created instance?
That is right. If one thread calls writer()
other thready may see f
as null
or f.y
as 0
because it does not respect safe publication:
3.5.3. Safe Publication Idioms
To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:
- Initializing an object reference from a static initializer;
- Storing a reference to it into a volatile field or AtomicReference;
- Storing a reference to it into a final field of a properly constructed > object; or
- Storing a reference to it into a field that is properly guarded by a lock.
Upvotes: 2