Skip to content
Advertisement

Accessing Java ThreadLocal object from a class other than where it was declared

I’m declaring a ThreadLocal object and setting a value like below.

Public Class Blah {

private ThreadLocal<Set<Integer>> numberThreaLocalObj= new ThreadLocal<>();

  void setValue() {
    Set<Integer> numberSet = new HashSet<>();
    numberSet .add(1);
    threaLocalObj.set(numberSet) 
  }
} 

Is there anyway to reference this numberThreaLocalObj variable outside of this class within the same thread?

I’ve found some code the seems to clear ALL the threadlocals, but I just need to clear this particular Threadlocal variable based on a condition.

Unfortunately this is a inherited technical design.

EDIT – SOLUTION FOUND as outlined in my answer.

Advertisement

Answer

I can use the following code to identify the specific threadlocal object I’m interested in Code is used from a previous post, which was answered by @lyaffe https://stackoverflow.com/users/509566/lyaffe

My thread local object in another class

 private ThreadLocal<Set<Integer>> numberSetTL = new NamedThreadLocal<>("MY_NAMED_TL_NAME");

I’ve slightly modified the code to remove a specific Name. The ThreadLocal being removed would have to be a Spring NamedThreadLocal object.

 private void cleanThreadLocals() {
        try {
            // Get a reference to the thread locals table of the current thread
            Thread thread = Thread.currentThread();
            Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
            threadLocalsField.setAccessible(true);
            Object threadLocalTable = threadLocalsField.get(thread);

            // Get a reference to the array holding the thread local variables inside the
            // ThreadLocalMap of the current thread
            Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
            Field tableField = threadLocalMapClass.getDeclaredField("table");
            tableField.setAccessible(true);
            Object table = tableField.get(threadLocalTable);

            // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
            // is a reference to the actual ThreadLocal variable
            Field referentField = Reference.class.getDeclaredField("referent");
            referentField.setAccessible(true);

            for (int i=0; i < Array.getLength(table); i++) {
                // Each entry in the table array of ThreadLocalMap is an Entry object
                // representing the thread local reference and its value
                Object entry = Array.get(table, i);
                if (entry != null) {
                    // Get a reference to the thread local object and remove it from the table
                    ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
                    if(threadLocal instanceof NamedThreadLocal) {

                        if("MY_NAMED_TL_NAME".equalsIgnoreCase(threadLocal.toString())) {
                            threadLocal.remove();
                            LOG.debug(tlName + " - ThreadLocal found and removed.");
                        }

                }
                }
            }
        } catch(Exception e) {
            // We will tolerate an exception here and just log it
            throw new IllegalStateException(e);
        }
    }
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement