There are a few questions on this subject, but most skirt around this issue because it's not the intent of the question.
If I have a static volatile in my class:
private static volatile MyObj obj = null;
and in a method below I do:
public MyObj getMyObj() {
if (obj == null) {
obj = new MyObj();// costly initialisation
}
return obj;
}
will I need to synchronize to ensure only one thread writes to the field, or will any writes be immediately visible to other threads evaluating the obj == null
conditional?
To put it another way: does volatile get you around having to synchronize access to writes on a static variable?
Effectively, a variable declared volatile must have it's data synchronized across all threads, so that whenever you access or update the variable in any thread, all other threads immediately see the same value.
You do need to make m2 synchronized. Otherwise someone can call that method at the same time. I am assuming m2 would be considered for being synchronized, otherwise it is a moot point.
Even if the static variables are shared variables, but in different thread there can be different values for a static variable in the local cache of a thread. To make it consistent for all threads, just declare it as static volatile . So each time it will fetch from main memory.
Noncompliant Code Example However, volatile flag still fails to provide the atomicity and visibility guarantees needed for synchronization primitives to work correctly. The volatile keyword does not promise to provide the guarantees needed for synchronization primitives.
You'd definitely need some sort of locking to ensure that only one thread writes to the field. Regardless of the volatility, two threads can both "see" that obj
is null, and then both start initializing with your current code.
Personally I'd take one of three options:
Initialize on class load (knowing that that will be lazy, but not as lazy as waiting until getMyObj
is first called):
private static final MyObj obj = new MyObj();
Use unconditional locking:
private static MyObj obj;
private static final Object objLock = new Object();
public static MyObj getMyObj() {
synchronized(objLock) {
if (obj == null) {
obj = new MyObj();
}
return obj;
}
}
Use a nested class for laziness that way:
public static MyObj getMyObj() {
return MyObjHolder.obj;
}
private static class MyObjHolder {
static final MyObj obj = new MyObj();
}
Yes, you should absolutely synchronize (or use a better idiom like the Singleton Holder idiom). Otherwise you run the risk of multiple threads initializing your object multiple times (and then subsequently using different instances).
Consider a sequence of events like this:
getMyObj()
and sees that obj == null
getMyObj()
and sees that obj == null
new MyObj()
- let's call it objA
new MyObj()
- let's call it objB
objA
to obj
objB
to obj
(which is not null
anymore at this point, so the reference to objA
, assigned by Thread A, is overwritten)getMyObj()
and starts to use objA
getMyObj()
and starts to use objB
This scenario can happen with any number of threads. Note that although here, for the sake of simplicity, I assumed a strict ordering of events, in a real multithreaded environment events 1-2, 3-4 and/or 7-8 can partly or fully overlap in time, without changing the end result.
An example to the 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 to be safe, as INSTANCE
is final
. The Java memory model guarantees that final
fields are initialized and made visible correctly to any number of threads, upon loading the containing class. Since LazyHolder
is private
and is referenced only by getInstance()
, it will only get loaded when getInstance()
is first called. And at that point, INSTANCE
is initialized in the background and published safely by the JVM.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With