Card 05/ 09
Memory Visibility: What One Thread Can See of Another's Writes
A write that happened, and that another thread may never see, even though nothing interleaved.
Visibility is whether a value one thread writes can be seen by another thread, and when. Without something that forces it, Java does not promise that another thread ever sees a write. That is a second way shared state goes wrong, separate from a race, where two threads interleave in the middle of one update.
A worker loop checks a boolean flag on every pass. Another thread sets the flag to true. The loop keeps going, for minutes, on a value that was changed long ago:
class Worker implements Runnable {
boolean stopped = false;
public void run() {
while (!stopped) { doWork(); }
}
void stop() { stopped = true; }
}Nothing interleaved and nothing was lost. The write happened, and it is not visible to the thread that needs it.
Each processor core has its own caches, and the compiler and the processor may both reorder instructions and keep values in registers, as long as a single thread's own view stays consistent. Nothing in that promise says anything about what a second thread sees, or when.
| Compared on | A race | A visibility problem |
|---|---|---|
| What went wrong | Two threads interleaved mid-operation | A write is not seen by another thread |
| Symptom | A wrong value | A stale value, sometimes forever |
| Fixed by | Making the operation atomic, so no thread can see it half done | Publishing the write |
| Shows up | Under load | Often only after the code is optimised, during warm-up |
So "it works on my machine" is even less reassuring here than usual. A visibility bug often appears only once the virtual machine has decided a loop is hot enough to optimise, well after its first thousand passes.
← → move through sections and cards