/*
 * Copyright (C) 2011-2014 Chris Vest (mr.chrisvest@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package stormpot;

import org.junit.Test;
import org.junit.Ignore;

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?
   */
  @Ignore
  @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.
  }
}

Add an example of how ThreadLocal values are cleared by the GC