The below code snippet is usually used to initiate some private member variables lazily.
class SomeClass {
private Resource resource = null;
public Resource getResource() {
if (resource == null)
resource = new Resource();
return resource;
}
}
This is a very common use case, for example most of the time, your code might not need to use resource, so why to initiate this variable if it is too costly. Instead only initiate it when necessary.
This however will not work for multi-threaded applications, as there is a potential race condition. Two threads can see that resource is null and one thread override the resource variable initiated by another thread. Simple solution is to use Synchronized access, like
class SomeClass {
private Resource resource = null;
public Resource Synchronized getResource() {
if (resource == null)
resource = new Resource();
return resource;
}
}
But this is now slow because whether the resource is already being initiated or not, any calls to getReource will synchronized all the threads.
The smarter solution is to use Double Checking idiom something like this -
class SomeClass {
private volatile Resource resource = null;
public Resource getResource() {
if (resource == null) {
synchronized {
if (resource == null)
resource = new Resource();
}
}
return resource;
}
}
However, because of the Memory model of JAVA specification, the above mentioned code might work in one JVM but might fail at times. If you remove the volatile keyword, it is definitely broken, but even if you keep the volatile keyword, it is not certain that it will work.
So what is the solution ? The author at the javaworld mentions that we should avoid the lazy initialization and the following code -
class SomeClass {
public static Resource resource = new Resource();
}
But the problem with this code is - whether you need or not, resource will be always initialized.
According to me, better way to use lazy initialization is to use "holder-class" idiom as explained in Effective Java by Joshua Bloch. It works like this -
class SomeClass {
private static class FieldHolder {
static final Resource field = new Resource();
}
public Resource getResource() {
return FieldHolder.field;
}
}
There is no synchronization, so no added cost. When the getResource method will be called for the very first time, it initiates the FieldHolder class for the very first time.
No comments:
Post a Comment