I explored Facebook open source device-year-class and found something interesting I wanted to ask.
It's pretty simple class that do some calculating and returns the year of you device
public class YearClass {
.
.
private volatile static Integer mYearCategory;
public static int get(Context c) {
if (mYearCategory == null) {
synchronized(YearClass.class) {
if (mYearCategory == null) {
mYearCategory = categorizeByYear(c);
}
}
}
return mYearCategory;
}
}
Why they check twice the mYearCategory == null
condition and why this variable declared volatile
? Its not initialised from different threads and we don't have changes to that value in the app life time, we just retrieve it for the first time... why its so important to make sure we read/write it from/to memory, what would happened if it was without volatile
. Also why we need to synchronized
it? there is no risk that other Thread can change it, it's just for reading.
Why have static volatile variable?
If you access a static value through multiple threads, each thread can have its local cached copy. To avoid this you can declare the variable as static volatile and this will force the thread to read each time the global value.
Now coming to your second question. Why is there checking of null twice? This is called double-checked locking optimization.
What is double checked locking?
public static int get(Context c) {
if (mYearCategory == null) {
synchronized(YearClass.class) {
if (mYearCategory == null) {
mYearCategory = categorizeByYear(c);
}
}
}
return mYearCategory;
}
Consider, the first call to get(Context c) will create the object and only the few threads trying to access it during that time need to be synchronized; after that all calls just get a reference to the member variable. Since synchronizing a method could in some extreme cases decrease performance by a factor of 100 or higher,the overhead of acquiring and releasing a lock every time this method is called seems unnecessary: once the initialization has been completed, acquiring and releasing the locks would appear unnecessary. Many programmers have attempted to optimize this situation in the following manner: