java - java中InheritableThreadlocal值自动改变

标签 java threadpool thread-local

我使用 InheritableThreadlocalHashMap 来存储我的所有线程局部变量。

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(它因内存泄漏而臭名昭著)

我尝试并重试在开发服务器中重现该问题,但未能成功。而且我不想冒险在生产服务器中测试这个。

最佳答案

您的 map 在父线程中实例化。 InheritedThreadLocal 值被“取下”到子线程。

虽然多个子线程可能并行执行,特别是。如图所示,一个线程可以将“MyKey”设置为 null,而另一个子线程正在读取它。

所以这是一个真正的问题。您应该在设置和读取之间同步代码。或者使用普通的ThreadLocal。

顺便说一句。您应该同步对 map 的访问。

关于java - java中InheritableThreadlocal值自动改变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48822169/

相关文章:

java - 如何使用 `adb` 仅为一个用户安装开发应用程序?

java - 为什么缓存线程池会创建两个线程,为什么关闭它会改变这种情况?

java - Runtime.getRuntime().availableProcessors() 可以返回 0 吗?

java - 为什么我们要在 spring 中使用自定义作用域?什么时候需要?

java - 将 "current user"保留在 threadlocal 中

java - ThreadLocal 与 Runnable 中的局部变量

Java - IzPack 和 EOFException

java - 从 1.0 迁移到 2.0 时,HttpEntity 出现 `application/xml` 错误

java - 缓存 URL 内容

java - 同步线程池ExecutorService