Yes, you should absolutely synchronize (or use a better idiom such as the Singleton Holder idiom ). Otherwise, you risk multiple threads initializing your object several times (and then subsequently using different instances).
Consider a sequence of events like this:
- Thread A enters
getMyObj() and sees that obj == null - Thread B enters
getMyObj() and sees that obj == null - Thread A builds a
new MyObj() - let him call it objA - Thread B creates a
new MyObj() - let him call it objB - Topic A designates
objA - obj - Thread B assigns
objB to obj (which is not null anymore at this point, so the link to objA assigned by thread A is overwritten) - Topic A exits
getMyObj() and starts using objA - Thread B terminates
getMyObj() and starts using objB
This scenario can happen with any number of threads. Please note that although I have adopted a strict order of events for simplicity, in a real multi-threaded environment, events 1-2, 3-4 and / or 7-8 can partially or completely overlap in time without changing the end of the result.
Example to holder idiom:
public class Something { private Something() { } private static class LazyHolder { public static final Something INSTANCE = new Something(); } public static Something getInstance() { return LazyHolder.INSTANCE; } }
This is guaranteed since INSTANCE is final . The Java memory model ensures that final fields are initialized and displayed correctly for any number of threads when loading the containing class. Since LazyHolder private and only refers to getInstance() , it will only load the first time getInstance() called. And at this point, INSTANCE initialized in the background and the JVM is safely published.
Péter Török
source share