我正在将InheritableThreadlocal
与HashMap
一起用于存储我的所有threadlocals。
class MyThreadLocalMap {
private final static ThreadLocal<HashMap<String, Object>> THREAD_VARIABLES = new InheritableThreadLocal<HashMap<String, Object>>() {
@Override
protected HashMap<String, Object> initialValue() {
return new HashMap<>();
}
};
public static Object get(String name) {
return THREAD_VARIABLES.get().get(name);
}
public static Object set(String name, Object value) {
Object currentValue = get(name);
THREAD_VARIABLES.get().put(name, value);
return currentValue;
}
}
直到最后一天出现一个奇怪的错误之前,这一直很好。
我正在使用tomcat服务器来运行我的Web应用程序。我使用
ScheduledThreadPoolExecutor
创建了一个线程池并在多个线程中运行一个任务。我的代码的简短形式与此类似。MyThreadLocalMap.set("MyKey", 1);
....
....
Object obj = MyThreadLocalMap.get("MyKey");
if(!Integer.valueOf(1).equals(obj))
throw new Exception("threadlocal mismatch!");
....
....
MyThreadLocalMap.set("MyKey", null);
上面的代码将在多个线程中执行,并且由于我正在使用线程池,因此将重复使用相同的线程。
奇怪的是,在大约5个线程成功完成执行之后,其中一个线程引发了“ threadlocal mismatch”异常!
我主要怀疑是使用InheritableThreadLocal(臭名昭著的内存泄漏)
我尝试并尝试在开发服务器中重现该问题,但我做不到。而且我不想冒险在生产服务器中进行测试。
最佳答案
您的地图在父线程中实例化。 InheritedThreadLocal值“记入”子线程。
虽然多个子线程可能在并行esp中执行。如图所示,一个线程可以将“ MyKey”设置为null,而另一个子线程正在读取它。
所以这是一个真正的问题。您应该在设置和读取之间同步代码。或使用普通的ThreadLocal。
顺便说一句。您应该同步访问地图。