如何在没有实际执行的情况下测试ThreadLocal是否已初始化?
我想测试ThreadLocal
是否已经初始化而没有实际初始化它。 当然,代码需要是线程安全的。 理想情况下我想要这样的东西:
class TestableThreadLocal extends ThreadLocal { public boolean isInitialized() { ... } }
但是我该如何实现这种方法呢?
编辑:动机:我已经将一个ThreadLocal
子类ThreadLocal
覆盖initialValue()
。 但是,我并不总是需要初始化,特别是因为它可能会导致多类加载器环境中的内存泄漏。 一个简单的测试可以帮助我编写代码以避免意外初始化。
我倾向于使用简单的规则来避免类加载器泄漏,不可否认它们很麻烦,但有一些包装并没有那么糟糕。 是的,泄漏是邪恶的。
- 永远不要覆盖
initialValue
– 你只是在寻找麻烦,只是忘了它存在。 - 除非你做
threadLocal.set(xxx); try{...process...}finally{threadLocal.set(null);}
否则不要在ThreadLocal中存储非系统/非bootstap类threadLocal.set(xxx); try{...process...}finally{threadLocal.set(null);}
threadLocal.set(xxx); try{...process...}finally{threadLocal.set(null);}
- 如果仍然覆盖initialValue,请使用
threadLocal.remove()
而不是threadLocal.set(null)
- 或者使用
WeakReferene
(即ThreadLocal
)作为保留硬引用的池中的值。 它可能看起来很直观但是一旦清除了池,值就会消失,并且类可以自由地进行GC>
我意识到post不是对你的问题的直接回复,但是没有简单的方法来实现你想要的东西并防止漏洞。
思考:
- 如果调用
ThreadLocal.get
,则初始化该值。 - 如果你不想初始化它,你不需要存储的值(根本不存在)
- 如果你想避免初始化,似乎开始的地方是重写
get
,而不是initialValue
。 - 采取不同的轨道 – 你真的需要inheritance
ThreadLocal
而不是收容吗?
执行此操作的几种可能方法之一将涉及reflection,因为ThreadLocal没有可让您知道值是否已初始化的API。
当然可以使用reflection“编码”它。 但是,所有常见的警告都适用。 您的reflection代码将高度依赖于java.lang.ThreadLocal及其非公共成员的实现细节。 JDK供应商改变实施的那一刻,你的代码就会崩溃。
你对最初的问题感到困惑。 ThreadLocal是您正在创建的还是已由其他人提供的API?
如果您正在创建ThreadLocal,那么我假设您已经知道必须覆盖initialValue()以便您可以提供初始值。
在这种情况下,您始终可以跟踪是否已调用该值并已创建该值。
我认为下面这段代码会做你想要的:
MyThreadLocal extends ThreadLocal { Map myThreadMap = new HashMap(); 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的线程消失时,键将被删除。