Thread-safe but fast access to an "eventually final" variable?
java, java-memory-model, synchronization
Solution
A note on volatile: marking a variable volatile is cheaper than using synchronization (it does not involve locks) and is generally cheap enough that you won't notice. In particular, on x86 architectures, reading a volatile variable does not cost more than reading a non-volatile variable. However writing to a volatile is more expensive and the fact that the variable is volatile might prevent some compiler optimisations.
So using volatile is probably the option that gives you the best performance/complexity ratio in your scenario.
You don't have that many alternatives. In the end it boils down to ensuring a safe publication of your worker. And safe publication idioms include:
- initialising the instance from a static initialiser
- marking the reference to the instance as final
- marking the reference to the instance as volatile
- synchronizing all accesses
In your case, only the last two options are available and using volatile is more efficient.
Problem
I have a server somewhat like this: ``` class Server { private WorkingThing worker; public void init() { runInNewThread({ // this will take about a minute worker = new WorkingThing(); }); } public Response handleRequest(Request req) { if (worker == null) throw new IllegalStateException("Not inited yet"); return worker.work(req); } } ``` As you can see, there are threads handling requests and a thread initing the server. Requests can come in before initing has finished, therefore there is the check with an `IllegalStateException`. Now, to make this thread safe (so request handler threads don't see a stale, `null`-valued, version of `worker` just after init), I'd have to make worker volatile, synchronize on it, or some such. However, after the init has completed, `worker` won't ever change again, so it's effectively final. Therefore, it seems like any lock contention that may occur would be a waste. So, what's the most efficient thing I can do here? Now I know it doesn't really matter in a practical sense (with all the heavy lifting of reading a network request, etc, what does a single lock matter?), but I'd like to know out of curiosity.