Reputation: 22045
I have a web app where I load components lazily. There is a lot of
static Bla bla;
...
if(bla == null)
bla = new Bla();
spread throughout the code. What do I need to do to make sure this is thread safe? Should I just wrap anytime I do one of these initializations in a synchronized
block? Is there any problem with doing that?
Upvotes: 1
Views: 2669
Reputation: 4150
Assuming you are using Java 1.5 or later, you can do this:
private static volatile Helper helper = null;
public static Helper getHelper() {
if (helper == null) {
synchronized(Helper.class) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
That is guaranteed to be threadsafe.
I recommend you read this to understand why the var HAS to be volatile, and the double check for null is actually needed: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Upvotes: 2
Reputation: 31903
The best solution for lazy loading on a static field, as described in Effective Java [2nd edition, Item 71, p. 283] and Java Concurrency in Practice [p. 348], is the Initialization on demand holder idiom:
public class Something {
private Something() {
}
private static class LazyHolder {
private static final Something something = new Something();
}
public static Something getInstance() {
return LazyHolder.something;
}
}
Upvotes: 5
Reputation: 308763
I'd ask why you think it's necessary to load these lazily. If it's a web app, and you know you need these objects, why would you not want to load them eagerly once the app started up?
Please explain the benefit that lazy loading is providing. If it's static, is there ever a possibility that you won't initialize these objects? If the answer is no, I'd challenge the design and recommend that you load eagerly on start-up.
Upvotes: 0
Reputation: 830
It is tricky to use volatile variable.
It's described here: http://www.ibm.com/developerworks/java/library/j-dcl.html
Example cited from above link:
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
{
v = new Vector();
inUse = true;
//...
}
public static Singleton getInstance()
{
return instance;
}
}
will work 100% and is much more clear (to read and to understand) comparing to double checking and other approaches.
Upvotes: 3
Reputation: 9086
Because bla is static, it can be accessed from different instances of the containing class
and code like
synchronized{...}
or synchronized(this){...}
does not defend against this. You must obtain a lock on the same object in all cases so for example synchronized(bla){...}
Upvotes: 0
Reputation: 12819
The best way is indeed to enclose everything in a synchronized block, and declare the variable volatile, as in:
private static volatile Bla bla;
synchronized{
if(bla == null) bla = new Bla();
}
If you really need to have only one single instance assigned to the bla
at any time you web application is running, you have to keep in mind the fact a static
keyword applied to a variable declaration only ensures there will be one per classloader that reads the class definition of the class defining it.
Upvotes: 0
Reputation: 91881
The lazy instantiation is only really a part of the problem. What about accessing these fields?
Typically in a J2EE application you avoid doing this kind of thing as much as you can so that you can isolate your code from any threading issues.
Perhaps if you expand one what kind of global state you want to keep there are better ways to solve the problem.
That being said, to answer your question directly, you need to ensure that access to these fields is done synchronized, both reading and writing. Java 5 has better options than using synchronized in some cases. I suggest reading Java Concurrency in Practice to understand these issues.
Upvotes: 1