Доступ к Java ThreadLocal объекту из класса, отличного от того, где он был объявлен - PullRequest
0 голосов
/ 21 апреля 2020

Я объявляю объект ThreadLocal и задаю значение, как показано ниже.

Public Class Blah {

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

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

Есть ли в любом случае ссылка на эту переменную numberThreaLocalObj вне этого класса в том же потоке?

Я нашел некоторый код, который, кажется, очищает ВСЕ локальные потоки, но мне просто нужно очистить эту конкретную переменную Threadlocal на основе условия.

К сожалению, это унаследованный технический проект.

РЕДАКТИРОВАТЬ - РЕШЕНИЕ НАЙДЕНО, как указано в моем ответе.

Ответы [ 2 ]

2 голосов
/ 21 апреля 2020

Тот факт, что это локальный поток, не имеет значения. Вы спрашиваете: могу ли я получить доступ к закрытому полю из другого класса?

Ответ: Не совсем. Если у вас есть экземпляр Blah, для которого вы хотите получить доступ к этому полю (это нестатическое поле c; следовательно, для каждого экземпляра Blah существует один поток), вы можете использовать java .lang.reflection:

Field f = Blah.class.getDeclaredField("numberThreaLocalObj");
f.setAccessible(true);
ThreadLocal<?> t = f.get(someInstanceOfBlah);
t.set(null);

сделает это, как только вы добавите соответствующих охранников исключений.

0 голосов
/ 24 апреля 2020

Я могу использовать следующий код для идентификации указанного c объекта threadlocal, который меня интересует. Код используется из предыдущего поста, на который ответил @lyaffe { ссылка }

Мой локальный объект потока в другом классе

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

Я немного изменил код, чтобы удалить указанное c Имя. Удаляемый ThreadLocal должен быть объектом Spring NamedThreadLocal.

 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);
        }
    }
...