【问题标题】:Accessing Java ThreadLocal object from a class other than where it was declared从非声明位置的类访问 Java ThreadLocal 对象
【发布时间】:2020-04-21 00:42:52
【问题描述】:

我正在声明一个 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 变量?

我发现一些代码似乎可以清除所有线程局部变量,但我只需要根据条件清除这个特定的线程局部变量。

很遗憾,这是一种继承的技术设计。

编辑 - 我的回答中概述的解决方案。

【问题讨论】:

    标签: java multithreading threadpool thread-local


    【解决方案1】:

    它是一个线程本地的事实是无关紧要的。您在问:我可以从另一个类访问私有字段吗?

    答案是:并非如此。如果您有想要访问此字段的 Blah 实例(它是一个非静态字段;因此,每个 Blah 实例都有一个 threadlocal),您可以使用 java.lang.reflection:

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

    一旦你添加了适当的异常保护,就会这样做。

    【讨论】:

      【解决方案2】:

      我可以使用以下代码来识别我感兴趣的特定线程本地对象 代码取自之前的帖子,@lyaffe https://stackoverflow.com/users/509566/lyaffe回复了

      我在另一个类中的线程本地对象

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

      我稍微修改了代码以删除特定名称。被移除的 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);
              }
          }
      

      【讨论】:

        【解决方案3】:

        您可以在类中将 ThreadLocal 变量作为静态变量,并在整个应用程序中全局访问它。来自官方 Spring 文档的示例

        https://github.com/spring-projects/spring-data-keyvalue-examples/blob/00e1930be9d8c056f654c685e01eaa2ce49f0beb/retwisj/src/main/java/org/springframework/data/redis/samples/retwisj/RetwisSecurity.java#L26

        不要忘记清除 ThreadLocalExecutor 处理程序中的 ThreadLocal 变量(使用 afterExecute() 将在 Thread 释放到 ThreadPool 后执行),如下链接的第 5.1 节所示:

        https://www.baeldung.com/java-threadlocal

        【讨论】:

          猜你喜欢
          • 2014-05-05
          • 1970-01-01
          • 1970-01-01
          • 2011-08-25
          • 1970-01-01
          • 1970-01-01
          • 2019-11-21
          • 2023-03-16
          • 1970-01-01
          相关资源
          最近更新 更多