9

我想测试 aThreadLocal是否已被初始化而没有实际初始化它。当然,代码需要是线程安全的。理想情况下,我想要这样的东西:

class TestableThreadLocal<T> extends ThreadLocal<T> {
    public boolean isInitialized() {
        ...
    }
}

但是我将如何实现这个方法呢?

编辑:动机:我将 a 子类化为ThreadLocaloverride initialValue()。但是,我并不总是需要初始化,特别是因为它可能导致多类加载器环境中的内存泄漏。一个简单的测试将帮助我编写代码以避免意外初始化。

4

4 回答 4

11

我倾向于使用简单的规则来避免类加载器泄漏,诚然它们很麻烦,但有一些包装它并没有那么糟糕。是的,泄漏是邪恶的。

  • 永远不要覆盖initialValue- 你只是在自找麻烦,只是忘记它的存在。
  • 不要在 ThreadLocal 中存储非系统/非引导类,除非你这样做threadLocal.set(xxx); try{...process...}finally{threadLocal.set(null);}
  • 如果您仍然覆盖 initialValue,请使用threadLocal.remove()notthreadLocal.set(null)
  • 或使用WeakReferene(即 ThreadLocal <WeakReference<Foo>>)来自保留硬引用的池中的值。它可能看起来不直观,但是一旦池被清除,值就会消失,并且类可以自由地被 GC'd

我意识到这篇文章并不是对您的问题的直接答复,但是没有简单的方法可以实现您的愿望并防止泄漏。

于 2012-08-06T10:43:19.120 回答
2

想法:

  • 如果ThreadLocal.get被调用,则值被初始化。
  • 如果您不希望它初始化,则不需要存储的值(根本,永远)
  • 如果你想避免初始化,似乎开始的地方是通过覆盖get,而不是initialValue.
  • 采取不同的方式——你真的需要继承ThreadLocal而不是遏制吗?
于 2012-08-12T01:35:03.390 回答
1

执行此操作的少数可能方法之一将涉及反射,因为 ThreadLocal 没有让您知道值是否已初始化的 API。

当然可以使用反射“编码”它。但是,所有通常的警告都适用。您的反射代码将高度依赖于 java.lang.ThreadLocal 及其非公共成员的实现细节。JDK 供应商更改实现的那一刻,您的代码就会中断。

于 2012-07-14T17:59:32.437 回答
1

我对你最初的问题感到困惑。ThreadLocal 是您正在创建的还是已经由其他 API 提供的?

如果您正在制作 ThreadLocal,那么我假设您已经知道您必须覆盖 initialValue() 以便您可以提供初始值。

在这种情况下,您始终可以跟踪是否已调用它并创建了值。

我认为像下面这样的代码会做你想要的:

MyThreadLocal<T> extends ThreadLocal<T>{

   Map<Thread,Boolean> myThreadMap = new HashMap<Thread,Boolean>();

   protected T initialValue(){
         synchronized(myThreadMap){
               T value =  ... your code to create initial value
               myThreadMap.put(Thread.currentThread(),true);
               return T;
         }
   }

   public boolean containsThreadValues(){
          synchronized(myThreadMap){
                 return myThreadMap.isEmpty();
          }
   }

   public boolean isInitializedForThisThread(){
         synchronized(myThreadMap){
                 return myThreadMap.get(Thread.currentThread())==true;
         }
   }


}

myThreadMap 将始终包含旧键,即使对于死线程也是如此。如果您想清除旧密钥,请将其替换为 WeakHashMap。然后,随着曾经使用 ThreadLocal 的线程消失,密钥将被删除。

于 2012-08-13T07:33:49.350 回答