繁体   English   中英

没有为 java 中的下一个线程清除 ThreadLocal 值

[英]ThreadLocal value not cleared for the next thread in java

我正在运行 web 服务,该服务至少接收 200 RPS。 基于该操作,我们为少数操作提供 root 访问权限,并使用以下代码。

private static final ThreadLocal<String> rootContext = new ThreadLocal<String>();

public Optional<String> getRunner() {
    if (rootContext.get() != null) {
        return rootContext.get();
    } else {
        return getCurrentRunner();
    }
}

public void rootAccess(Runnable runnable) {
    rootContext.set("root");
    runnable.run();
    rootContext.set(null);
}

getCurrentRunner()方法将根据请求返回实际的调用者。 问题是 200 个请求中有 1 个返回root而不是实际的调用者。

我注意到的一件事是,我没有使用 threadlocal.remove(),而是将该值设置为 null。 预计 getRunner() rootContext.get() != null条件将失败并返回实际的调用者。

如何解决这个问题? 设置rootContext.remove()会解决这个问题吗? 如果是,如何?

谢谢您的帮助

您的rootAccess方法有两个问题:

  1. 如果 Runnable 抛出 RuntimeException ThreadLocal 不会被删除(可能是你所看到的)
  2. rootContext.set(null); 仍然保持与正在运行的线程关联的ThreadLocal实例,最好做rootContext.remove();

更正这两点意味着将rootAccess()更改为

public void rootAccess(Runnable runnable) {
    rootContext.set("root");
    try {
        runnable.run();
    } finally {
        rootContext.remove();
    }
}

为什么是rootContext.set(null); 一般有问题吗?

每个线程基本上都保留一个类似于Map<ThreadLocal, ?>的数据结构,其中键是您的ThreadLocal实例( rootContext ),值是您通过rootContext.set(xx);

如果你调用rootContext.set(null); 那么rootContext仍然在 map 中,因此执行此行的每个线程(来自线程池,意味着线程长时间运行)都会保留对 rootContext 的引用,这反过来可能会阻止rootContext卸载。

如果你调用rootContext.remove(); rootContext 从rootContext中删除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM