Skip to content

Instantly share code, notes, and snippets.

@chrisvest
Created July 20, 2014 00:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisvest/32c691e51f891a35a1ca to your computer and use it in GitHub Desktop.
Save chrisvest/32c691e51f891a35a1ca to your computer and use it in GitHub Desktop.
ThreadLocals and weak references
import org.junit.Test;
import java.lang.ref.WeakReference;
import static org.junit.Assert.assertNull;
public class ThreadLocalWeakRefTest {
/**
* Many Java web servers and containers go out of their way to find and null
* out ThreadLocals that an application might have created. Question is, is
* that really necessary?
*/
@Test public void
threadsWeaklyReferenceThreadLocalValues() {
// Hypothesis: When we loose the reference to a ThreadLocal (e.g. by a
// web app being redeployed and getting a soft restart), and no other
// references to that object exists, then it should eventually be garbage
// collected.
Object obj = new Object();
ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();
WeakReference<Object> weakReference = new WeakReference<Object>(obj);
threadLocal.set(obj);
// The stack of every thread is a GC-root. We have a strong reference to
// obj through the variable on our stack. When we clear it out, the only
// strong reference that will be left, will be through the threadLocal.
obj = null;
// When we loose the reference to the threadLocal, then the values it
// referred to will no longer be strongly referenced by our thread.
threadLocal = null;
// Our obj is now in principle garbage, though we still have a
// weakReference to it. The GC does not yet know this, because only the
// threadLocal object itself is now weakly referenced. We clear out that
// weak reference with a run of the GC.
System.gc();
// The entry in our ThreadLocalMap is now stale. It still exists, and
// strongly references our obj, but it will be cleared next time our
// ThreadLocalMap does its clean-up procedure. We cannot invoke the
// clean-up procedure directly, but sufficient perturbation of the
// ThreadLocalMap will bring it about.
ThreadLocal<Object> a = new ThreadLocal<Object>();
a.set(new Object());
ThreadLocal<Object> b = new ThreadLocal<Object>();
b.set(new Object());
// The entry has now been removed, and our obj is now weakly referenced
// by our weakReference above. Invoking another round of GC will clear it.
System.gc();
// The obj has now been collected because all references are gone.
// We observe this by the weakReference being null.
assertNull(weakReference.get());
// This test passes on Java 6, 7 and 8, with default GC settings.
// I haven't tried alternative GC settings, but you are welcome to do that.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment