Effective Java Item66疑问:单线程写入时为何仍需同步读线程?
Great question—this is such a common sticking point when wrapping your head around Java's memory model, and Effective Java Item 66 cuts straight to the heart of the issue with that line about synchronization needing to cover both reads and writes. Let's break down exactly why this matters, even with only one thread handling writes.
1. Memory Visibility: Threads don't automatically see the latest values
Java's Memory Model (JMM) lets each thread cache variables in its own "working memory" instead of always reading directly from main memory. When a single thread writes to a variable, that update first goes to its local cache—and there's no guarantee when (or if) it gets flushed to main memory without synchronization.
On the read side, a thread might keep pulling the old, cached value from its own working memory forever, never catching the update from the writing thread. Synchronizing both operations fixes this:
- A synchronized write forces the thread to flush its local changes to main memory immediately.
- A synchronized read forces the thread to dump its cached value and pull the latest directly from main memory.
2. Instruction Reordering can break consistency
Even with a single writing thread, the JVM or CPU might reorder instructions to boost performance. Take this example:
public class Config { private boolean isInitialized; private String setting; // Only called by one thread public synchronized void setup() { setting = "production"; isInitialized = true; } // If this isn't synchronized... public String getSetting() { if (isInitialized) { return setting; // Might return null! } return "default"; } }
Without synchronizing getSetting(), the JVM could swap the order of setting = "production" and isInitialized = true. A reading thread might see isInitialized as true but read a null value for setting, because the assignment to setting hasn't been flushed to main memory yet from their perspective. Synchronization blocks this reordering by enforcing a happens-before relationship: all writes in the synchronized setup() are guaranteed to complete before any reads in a synchronized getSetting().
3. Synchronization is about communication, not just mutual exclusion
As Item 66 emphasizes, synchronization here isn't about stopping multiple threads from writing at the same time (since we only have one writing thread). It's about signaling state changes between threads. The synchronized blocks act as a handshake: "Hey, any thread reading this variable needs to see the absolute latest version written by the other thread."
Without that handshake, the JMM gives zero guarantees about when (or if) the reading thread will ever see the write.
实际上,除非读写操作都进行同步,否则同步不会产生效果。
— Effective Java (第2版), 条目66
内容的提问来源于stack exchange,提问作者SHB

