简体   繁体   English

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

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

I'm running a web service which is receiving 200 RPS at least.我正在运行 web 服务,该服务至少接收 200 RPS。 Based on the action, we provide root access for few operations and using the following code.基于该操作,我们为少数操作提供 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() method will return the actual caller based on the request. getCurrentRunner()方法将根据请求返回实际的调用者。 The problem is 1 request out of 200 requests returns root instead of the actual caller.问题是 200 个请求中有 1 个返回root而不是实际的调用者。

One thing I noticed is instead of using threadlocal.remove(), I'm setting that value as null.我注意到的一件事是,我没有使用 threadlocal.remove(),而是将该值设置为 null。 Expecting that, getRunner() rootContext.get() != null condition will fail and return the actual caller.预计 getRunner() rootContext.get() != null条件将失败并返回实际的调用者。

How to solve this?如何解决这个问题? Will setting rootContext.remove() solve this?设置rootContext.remove()会解决这个问题吗? If yes, how?如果是,如何?

Thanks for the help谢谢您的帮助

There are two problems with your rootAccess method:您的rootAccess方法有两个问题:

  1. if the Runnable throws a RuntimeException the ThreadLocal is not removed (probably what you are seeing)如果 Runnable 抛出 RuntimeException ThreadLocal 不会被删除(可能是你所看到的)
  2. rootContext.set(null); still keeps the ThreadLocal instance associated with the running thread, it is better to do rootContext.remove();仍然保持与正在运行的线程关联的ThreadLocal实例,最好做rootContext.remove();

Correcting this two points means to change rootAccess() to更正这两点意味着将rootAccess()更改为

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

Why is rootContext.set(null);为什么是rootContext.set(null); generally a problem?一般有问题吗?

Each thread basically keeps a data structure similar to a Map<ThreadLocal, ?> where the key is your ThreadLocal instance ( rootContext ) and the value is the value that you associate with it through rootContext.set(xx);每个线程基本上都保留一个类似于Map<ThreadLocal, ?>的数据结构,其中键是您的ThreadLocal实例( rootContext ),值是您通过rootContext.set(xx);

If you call rootContext.set(null);如果你调用rootContext.set(null); then rootContext is still in that map and therefore each thread (from a thread pool, meaning the thread is long running) that executed this line keeps a reference to rootContext which in turn might prevent class unloading.那么rootContext仍然在 map 中,因此执行此行的每个线程(来自线程池,意味着线程长时间运行)都会保留对 rootContext 的引用,这反过来可能会阻止rootContext卸载。

If you call rootContext.remove();如果你调用rootContext.remove(); the rootContext is removed from that map. rootContext 从rootContext中删除。

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

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