在 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 object
将用于完成其余的工作。以上给定值每次都不相同,可能因请求而异。我的问题:上述场景是线程安全的吗?不同的 Web 服务请求是否会共享相同的
company_id
和 user_id
因为这两个参数都持有相同的引用?那么就会很困惑。我应该使用非静态方法吗?我确实经历了下面的类似问题
Are non-synchronised static methods thread safe if they don't modify static class variables?
但我需要澄清这一点。
最佳答案
简而言之
它是安全的。
解释ThreadContext
是一个作用域为每个线程的映射。随便说一下,每个线程都有自己的映射实例,其他线程看不到这些值。见 https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html有关线程局部变量主题的更多详细信息。没关系,无论您在哪种方法中设置ThreadContext
是否静态。
有一个警告:Java 应用程序服务器/Web 服务器使用线程池和重用线程。这意味着一旦一个线程完成了它的 web 请求,它就会被重用来处理下一个请求。 ThreadContext
内的数据保留并且对下一个请求有效。为下一个请求保留数据通常是不可取的。您应该清除 ThreadContext
完成请求后:
try{
setLogParams(company_id, userId);
... // do your business logic
} finally {
clearLogParams(); // Something like ThreadContext.clear();
}
更新:我没有介绍静态/非同步方法部分,但这是对此的答案:
您的方法不会将参数存储在您自己的存储中;而是将它们存储在
ThreadContext
中.参数(无论它们是在静态方法还是非静态方法中)在调用和线程之间不重叠。参数的生命周期随着方法调用的结束而结束(只要您不存储数据,但引用是一个不同的主题)。如果您存储
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;
}
}
您必须同步所有方法调用以保证一对一的操作,这将有效地将您的整个系统变成一个行为类似于单线程但具有多线程和大量缺点的系统。
在同步方面,静态方法与静态变量无关。然而,在某些情况下,您可以调用行为不同的同步非静态方法,但这使我们离您的原始问题太远了。
关于java - 通过 Java 静态方法写入 log4j2 日志时包括 ThreadContext - 线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31202120/