Georges Berenger Georges Berenger - 20 days ago 7
Java Question

Test a weak reference before using it java

In a multithreaded Android project, I'm seeing code like this:

final WeakReference<MyClass> myClassObjectWeakRef =
new WeakReference<MyClass>(aMyClassObject);


...then somewhere else:

if (myClassObjectWeakRef.get() != null) {
myClassObjectWeakRef.get().someMethod();
}


I'm pretty sure there is a possible race condition between the check and the use of the reference, if the last strong reference to the object is released between the two in another thread, but I can't find any documentation or anyone which/who can confirm this better than with a "you're probably right".

I would think the only right way to test & use a weak reference is done like this:

MyClass myObject = myClassObjectWeakRef.get();
// we now have a strong reference, or null: standard checks apply.
if (myObject != null) {
myObject.someMethod();
}


I'm very confident that the second method is 100% safe, but I wonder if there is some Java/compiler sugar/magic that I don't know about, which would make the first method safe.

So, is the first method 100% safe, or not?

Answer

The first method is definitely unsafe. Each call to get is independent. There is nothing preventing the GC from clearing the weakly reachable object after the first get and before the second.

The javadoc states

Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references.

That can be at any point in time. Calling get(), which (potentially) pushes a reference to the object on the stack temporarily makes the object strongly reachable (it's on a thread's stack), but that reach-ability disappears the moment the comparison with null finishes. After that moment, the GC can determine that the object is weakly reachable and clear its reference. You'd then get a NullPointerException.

Use your second method. But note that by assigning it to a variable, you are making the referenced object strongly reachable.