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.