gpt4 book ai didi

java - 如何根据Sonar清理Java ThreadLocals?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:30:27 26 4
gpt4 key购买 nike

A Sonar自 2019 年 8 月 21 日起可用的规则 (squid:S5164/RSPEC-5164) 要求在不再使用时清理“ThreadLocal”变量。那么,让我们学习下面的类(JDK6 兼容):

public class ThreadLocalExample {

private static final ThreadLocal<NumberFormat> formats = new ThreadLocal<NumberFormat>() {
@Override
protected NumberFormat initialValue() {
final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
nf.setGroupingUsed(false);
return nf;
}
};

public static NumberFormat getFormatter() {
return formats.get();
}
}

Sonar 在 ThreadLocal 声明中报告了一个主要错误,解释如下:

"ThreadLocal" variables should be cleaned up when no longer used

ThreadLocal variables are supposed to be garbage collected once the holding thread is no longer alive. Memory leaks can occur when holding threads are re-used which is the case on application servers using pool of threads.

To avoid such problems, it is recommended to always clean up ThreadLocal variables using the remove() method to remove the current thread’s value for the ThreadLocal variable.

现在,我采用了 ThreadLocal 方法,以便尽可能地重用 NumberFormat 实例,避免每次调用都创建一个实例,所以我认为如果我调用remove() 在代码的某处,我会失去这个解决方案的所有优势。我错过了什么吗?非常感谢。

最佳答案

Sonar 就在这里。

每个线程都有自己的 ThreadLocal 状态,因此也有自己的 NumberFormat 实例。
所以在一般情况下,不清除状态中的数据可能是不可取的,因为线程可能会被重用(由服务器回收),并且前一个客户端的状态值可能与当前客户端不一致。
例如,某些客户端的格式可能是 US,其他客户端的格式可能是 FR,等等...除了一些线程可以实例化 ThreadLocal 类之外,其他线程不能。但是通过不清理状态,状态将仍然为可能不需要它们的线程使用内存。

好吧,在您的代码中,ThreadLocal 状态没有可变性,因为您为任何实例设置了状态,因此不太可能出现不一致的风险,只是内存“浪费”。

Now, I adopted the ThreadLocal approach in order to reuse NumberFormat instances as much as possible, avoiding the creation of one instance per call

您可以根据线程请求重用 ThreadLocal 状态。
所以如果你有 50 个线程,你就有 50 个状态。
在网络应用程序中,服务器将客户端 HTTP 请求映射到一个线程。
因此,您不会仅在 1 个 http 请求的范围内创建格式化程序的多个实例。这意味着,如果您通过请求处理使用格式化程序一两次,ThreadLocal 缓存不会带来很大的值(value)。但是如果你用的多了,用起来就有意义了。

so I think if I called remove() somewhere in the code, I would lose all the advantages of this solution

如果在请求处理完成后调用 remove() 将不会影响性能。您不会失去任何优势,因为您可能会在请求范围内多次使用格式化程序,并且只会在最后清理它。

您在 servlet 规范中有 Request Listener: https://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestListener.html .
您可以在 void requestDestroyed(ServletRequestEvent sre) 中执行此操作。

关于java - 如何根据Sonar清理Java ThreadLocals?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57749185/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com