In my application, I need to set a variable lazily since I don't have access to the necessary methods during class initialization, but I also need that value to be accessible across multiple threads. I know that I could use double-checked locking to solve this, but it seems like overkill. The method that I need to call to obtain the value is idempotent and the return value will never change. I'd like to lazily initialize the reference as if I were in a single-threaded environment. It seems like this should work since reads and writes to references are atomic.[1][2]
Here's some example code for what I'm doing.
// views should only be accessed in getViews() since it is
// lazily initialized. Call getViews() to get the value of views.
private List<String> views;
/* ... */
private List<String> getViews(ServletContext servletContext) {
List<String> views = this.views;
if (views == null) {
// Servlet Context context and init parameters cannot change after
// ServletContext initialization:
// https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContext.html#setInitParameter(java.lang.String,%20java.lang.String)
String viewsListString = servletContext.getInitParameter(
"my.views.list.VIEWS_LIST");
views = ListUtil.toUnmodifiableList(viewsListString);
this.views = views;
}
return views;
}
This question about 32-bit primitives is similar, but I want to confirm that the behavior is the same for references to objects like String
s and List
s.
Seemingly this should work fine since each thread will either see null
and recompute value (not a problem since the value never changes) or see the already computed value. Am I missing any pitfalls here? Is this code thread-safe?