I want to write a class where an instance field holds a large amount of data that is expensive to create. Because the object is time consuming to create I want separate instances to be able to reuse the object if it has already been computed for a different instance. On the other hand if all instances of the class are garbage collected, I want the large object to be able to be garbage-collected too.
I came up with code like the following.
public class Example {
private Example() {}
private static volatile Reference<List<Integer>> ref = new WeakReference<>(null);
public static List<Integer> get() {
List<Integer> list;
if ((list = ref.get()) != null)
return list;
synchronized (Example.class) {
if ((list = ref.get()) != null)
return list;
list = compute();
ref = new WeakReference<>(list);
return list;
}
}
private static List<Integer> compute() {
// Some expensive computation producing a List with millions of elements
}
}
Then you can make this list an instance field by doing
public class MyClass {
private final List<Integer> list = Example.get();
}
This code seems to work, but I am unsure if I am using volatile
, synchronized
, WeakReference
and the double-check idiom correctly. Can anybody see any problems with this code, or suggest an alternative/better way of achieving this?