我想测试一个ThreadLocal
是否已经初始化而没有实际初始化它。当然,代码需要是线程安全的。理想情况下,我想要这样的事情:
class TestableThreadLocal<T> extends ThreadLocal<T> {
public boolean isInitialized() {
...
}
}
但是我该如何实现这种方法?
编辑:动机:我已将ThreadLocal
子类化为覆盖initialValue()
。但是,我并不总是需要初始化,特别是因为它可能会导致多类加载器环境中的内存泄漏。一个简单的测试可以帮助我编写代码以避免意外初始化。
答案 0 :(得分:11)
我倾向于使用简单的规则来避免类加载器泄漏,不可否认它们很麻烦,但有一些包装并没有那么糟糕。是的,泄漏是邪恶的。
initialValue
- 你只是在寻找麻烦,只是忘记它存在。threadLocal.set(xxx); try{...process...}finally{threadLocal.set(null);}
threadLocal.remove()
而不是threadLocal.set(null)
WeakReferene
(即ThreadLocal <WeakReference<Foo>>
)获取保存硬引用的池中的值。它可能看起来很直观,但一旦清除了池,值就会消失,类可以自由地进行GC 我意识到这篇文章不是对你的问题的直接回复,但是没有简单的方法可以达到你想要的目的并防止泄密。
答案 1 :(得分:2)
思想:
ThreadLocal.get
,则初始化值。get
,而不是initialValue
来启动。ThreadLocal
而不是遏制吗?答案 2 :(得分:1)
执行此操作的几种可能方法之一将涉及反射,因为ThreadLocal没有可让您知道该值是否已初始化的API。
使用反射“编码”它当然是可能的。但是,所有常见的警告都适用。您的反射代码将高度依赖于java.lang.ThreadLocal及其非公共成员的实现细节。 JDK供应商改变实施的那一刻,你的代码就会崩溃。
答案 3 :(得分:1)
我对你最初的问题感到困惑。您正在创建的ThreadLocal是否已由其他人提供?
如果您正在创建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的线程消失时,键将被删除。