Created
July 20, 2014 00:46
-
-
Save chrisvest/32c691e51f891a35a1ca to your computer and use it in GitHub Desktop.
ThreadLocals and weak references
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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