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 Strings and Lists.
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?