在通过Java静态方法编写log4j2日志时包括ThreadContext—它是线程安全的吗?

在通过Java静态方法编写log4j2日志时包括ThreadContext—它是线程安全的吗?,java,web-services,concurrency,thread-safety,log4j,Java,Web Services,Concurrency,Thread Safety,Log4j,在web服务应用程序中,我使用静态方法设置log4j ThreadContext变量,用于记录日志,如下所示: public static void setLogParams(String company_id, String userId) { ThreadContext.put("company_id_val", company_id); ThreadContext.put("user_id_val", userId); } 每个web服务请求最初都将调用上述方法,然后lo

在web服务应用程序中,我使用静态方法设置log4j ThreadContext变量,用于记录日志,如下所示:

public static void setLogParams(String company_id, String userId) {
    ThreadContext.put("company_id_val", company_id);
    ThreadContext.put("user_id_val", userId);
}
每个web服务请求最初都将调用上述方法,然后
loj4j Logger对象
将用于完成其余的任务。上述给定值并非每次都相同,可能会因请求而异

我的问题:上面的场景是线程安全的吗?不同的web服务请求是否会共享相同的
公司id
用户id
,因为这两个参数都包含相同的引用?那就很混乱了。我应该改用非静态方法吗

我确实问了下面类似的问题


但是我需要澄清这一点。

参数的定义仅用于调用方法。参数不会在不同调用之间共享,即使来自同一线程

在几乎所有的影响下,参数都作为局部变量起作用。如果你这样做

public void myMethod(int i) {

在这两种情况下,
i
都是一个只能在该方法调用范围内访问的变量。如果再次创建该方法,将创建一个不同的独立副本

如果没有这种情况,您链接到的答案将毫无意义(事实上,几乎不可能有并发系统;想象一下,您将需要同步每个静态方法,如
Integer.parseInt(String)

很安全

解释
ThreadContext
是一个映射,作用域为每个线程。随便说,每个线程都有自己的映射实例,其他线程看不到这些值。有关线程局部变量主题的更多详细信息,请参阅。设置
ThreadContext
的方法是否是静态的并不重要

有一个警告:Java应用程序服务器/web服务器使用线程池并重用线程。这意味着一旦一个线程完成了它的web请求,它就会被重用来处理下一个请求。
ThreadContext
中的数据将保留,并对下一个请求有效。为下一个请求保留数据通常是不可取的。完成请求后,应清除
ThreadContext

try{
    setLogParams(company_id, userId);
    ... // do your business logic
} finally {
    clearLogParams(); // Something like ThreadContext.clear();
}
更新:我没有介绍静态/非同步方法部分,但以下是答案:

您的方法不会将参数存储在您自己的存储器中;而是将它们存储在
线程上下文中。参数(无论它们是在静态还是非静态方法中)在调用和线程之间不重叠。参数的生命周期随着方法调用的结束而结束(只要不存储数据,但引用是不同的主题)

如果您将
customer\u id
存储在一个静态变量中(例如,由您自己存储),您将遇到竞争条件:

class RequestDataHolder {
   // this is not thread safe since multiple threads access the same data
   public static String customer_id;

   public static void setLogParams(String company_id, String userId){
      RequestDataHolder.customer_id = customer_id;
   }
}
您必须同步所有方法调用,以保证一个接一个的操作,从而将整个系统有效地转变为一个行为类似于单线程但具有多线程和大量缺陷的系统


涉及同步时,静态方法与静态变量无关。但是,在某些情况下,您可以调用行为不同的同步非静态方法,但这会使我们远离您最初的问题。

谢谢,我编辑了这个问题。这会给你一个清晰的概念,谢谢。应该清除线程上下文以确保。(请注意,我稍微修改了问题)谢谢!这解释了很多。
class RequestDataHolder {
   // this is not thread safe since multiple threads access the same data
   public static String customer_id;

   public static void setLogParams(String company_id, String userId){
      RequestDataHolder.customer_id = customer_id;
   }
}