0

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?

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116

1 Answers1

0

Looks good to me, but I think the volatile is not necessary. At least if you are only assigning it from inside the synchronized block, the synchronization block should prevent memory consistency errors

gustf
  • 1,959
  • 13
  • 20