首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在通过Java编写ThreadContext日志时包括log4j2 --线程安全吗?

在通过Java编写ThreadContext日志时包括log4j2 --线程安全吗?
EN

Stack Overflow用户
提问于 2015-07-03 08:28:49
回答 2查看 10K关注 0票数 6

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

代码语言:javascript
运行
复制
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_iduser_id,因为这两个参数都包含相同的引用吗?那就会令人困惑。我应该用非静态方法代替吗?

我确实经历了以下类似的问题

Are non-synchronised static methods thread safe if they don't modify static class variables?

但我需要澄清这一点。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-07-03 08:49:51

总之

这是安全的。

解释

ThreadContext是一个映射,它的作用域是每个线程。随便说,每个线程都有自己的映射实例,其他线程看不到这些值。有关线程局部变量主题的详细信息,请参阅https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html。设置ThreadContext的方法是否是静态的并不重要。

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

代码语言:javascript
运行
复制
try{
    setLogParams(company_id, userId);
    ... // do your business logic
} finally {
    clearLogParams(); // Something like ThreadContext.clear();
}

更新:我没有介绍静态/不同步方法部分,但是下面是这个部分的答案:

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

如果您将customer_id存储在静态变量中(例如,按自己的方式存储),则会遇到争用条件:

代码语言:javascript
运行
复制
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;
   }
}

您必须同步所有方法调用,以保证一对一的操作,这些操作将有效地将整个系统转换为一个像单线程但具有多个线程和大量缺陷的系统。

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

票数 11
EN

Stack Overflow用户

发布于 2015-07-03 08:44:38

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

参数作为局部变量在几乎所有的效果中都起作用。如果你这样做了

代码语言:javascript
运行
复制
public void myMethod(int i) {

代码语言:javascript
运行
复制
public void myMethod() {
  int i;

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

如果没有这种情况,那么链接到的答案就没有什么意义了(事实上,并发系统几乎是不可能的;假设您需要同步每个静态方法,比如Integer.parseInt(String))。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31202120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档