Let's say I have a shared object with field
data. Multiple threads will share a reference to this object in order to access the field. The threads never access the object concurrently, though. Do I need to declare
data as volatile?
Such a situation would be the following:
Counterdefines a unique field
valueand one method
Given the very logic of the program, there is no concurrent access to the counter. The counter is however shared accross multiple threads. Must the counter be a volatile?
Another variant of the situation is when multiple threads manipulate an object X that is plain data, but alternate their temporal execution (so that X is never accessed concurrently) via another object Y that rely on concurrency control (
synchronize). Should fields of object X be volatile?
Studying the entire JLS chapter on the Java Memory Model is highly recommended – mandatory, in fact – for anyone doing concurrency in Java. Your case, specifically, is covered in JLS, 17.4.4:
"An action that starts a thread synchronizes-with the first action in the thread it starts."
This means that for your first scenario you don't need
volatile. However, it would be good practice to have it anyway to be robust to future changes to the code. You should really have a good reason not to have
volatile, which would be only in the case of an incredibly high read rate (millions per second at the very least).
the Java Memory Model and bytecode reordering does not guarantee that subsequent thread will see the incremented value of the counter. So if you work with single thread - you don't need to do anything with volatiles, but if several threads may read something from variable - you need to ensure visibility of changes to another threads either with volatile or with syncrhonization/locks.
Thread.start method imposes the barrier, so visibility is assured - and it may happen that you don't need that volatile stuff. But I would add it anyway.
Regarding the second part of your question: if you do not use volatile on your variable X, it is possible that a given thread will always use a locally cached version of the value of the variable. Your use of variable Y as a lock will work very well as a means to insure that the two threads do not write concurrently to X but can't guarantee that one of the threads won't be looking at stale data.
From the JLS: "A write to a volatile variable v synchronizes-with all subsequent reads of v by any thread". The way I read this is that the spec offers no guarantees about the reads to other variables besides v.
You've only told part of the story with the counter. The incrementing part of the counter seems fine -- as Marko points out, there is a HB edge at Thread.start. But who's reading this counter? If it's anybody other than these spawned threads, and you at all care about seeing an up-to-date value, then the field needs to be volatile. If the counter is a
double), you need it to be volatile even if you don't care about stale values, because otherwise you could get word tearing.
Mutations from a thread are guaranteed to become visible to other threads only when an happen-before relationship between the threads is established. When the relationship is established, all previous mutations become visible.
An object that isn't correctly synchronized when taken in isolation can be safe to use if another object correctly synchronizes accesses to it (see piggibacking in Java Concurrency in Practice).
In the two cases described in the question, I think no synchronization is needed:
Thread.startestablishes a happen-before relationship, so all mutations from previous threads are visible
If you know that an object X is never accessed concurrently, chances are there is an object Y that indirectly synchronizes accesses to X, so it's fine. The only unsafe case I see is if threads relay on time itself (e.g. with Thread.sleep or by looping until some time has elasped) to guarantee mutual exclusion: in this case there is no happen-before relationship that is established.