【问题标题】:InheritableThreadlocal value changes automatically in javaInheritableThreadlocal 值在 java 中自动更改
【发布时间】:2018-02-16 07:42:01
【问题描述】:

我正在使用 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(因内存泄漏而臭名昭著)

我尝试并重试在开发服务器中重现该问题,但我无法做到。而且我不想冒险在生产服务器中进行测试。

【问题讨论】:

    标签: java threadpool thread-local


    【解决方案1】:

    您的地图在父线程中实例化。 InheritedThreadLocal 值被“取消”到子线程。

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

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

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

    【讨论】:

    • 不,我从未从父线程访问过 MyThreadLocalMap。具体来说,线程池初始化代码位于不同的 jar 文件中。所以我相信每个子线程都应该有自己的地图副本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多