静态成员和实例方法同时介绍了多个请求



如果我将像logger对象这样的对象定义为类中的静态,请调用以下方法:

public class Manager
{    
    private static ClientLogManager log = new ClientLogManager();
    public void Log(string Message)
    {
         log.Debug(string Message);
    }
}

这是在类库项目中定义的。

我的理解是,在此应用程序的所有请求之间共享静态变量,因此共享日志对象。但是,方法调试本身不是静态的,而是对象是静态的,因此只有一个实例。这是正确的吗?

如果许多用户同时调用此代码,如果2个请求正在调用log.debug方法,那么第二请求的消息可以覆盖第一个请求的消息?

另外,用单身人士替换它更好吗?每个请求不是一个单身对象吗?

这是Clientlogmanager代码

  public class ClientLogManager
    {
        #region Member Variables
        private static readonly ILog _log = LogManager.GetLogger(typeof(ClientLogManager));
        #endregion
        #region Constructors
        public ClientLogManager()
        {
        }
        #endregion
        #region Public Methods
        public void Debug(string message)
        {
            _log.Debug(message);
        }
        #endregion
    }

如果许多用户同时调用此代码,如果2个请求正在调用log.debug方法,那么第二请求的消息可以覆盖第一个请求的消息?

是的,除非专门编写了记录器来支持这一点。大多数登录器都是为支持这一点而设计的,因此,除非您从头开始滚动的机会,否则它将同步所有内部写入(因此不必这样做)。如果您不确定,则应查看您使用的特定记录器的文档,以查看该文档是否会在同时写入时会支持或破裂。

"我的理解是,静态变量在此应用程序的所有请求之间共享,因此日志对象共享。" 正确,每个appdomain的静态成员仅有1个实例。

"但是,方法调试本身不是静态的,但是对象是静态的,所以此方法只有一个实例。这是正确的吗?" 该声明本身是正确的,但是...

它归结为:

  • 静态和实例方法"存在"仅在内存中一次,区别在于静态方法不需要该类别的类实例即可被执行,而实例方法则执行。

  • 如果可以同时处理多个请求,则必须在不同的线程。每个线程都有自己的调用堆栈,如果您使用线程执行方法呼叫,传递给该方法的参数放在该线程的呼叫堆栈上。

  • 这意味着,只要论点是估值(例如INT)还是一个不变的类型(例如在这种情况下,字符串)不能由另一个线程修改(因为它要么是从另一个线程中看不见的,要么无法修改)。因此,您不必担心这些消息在Manager.log()或clientlogmanager.debug()方法中混合在一起。

因此,您当前的管理器和客户端logmanager实现都是线程安全的(至少,如果_log实例是线程安全的,则是线程安全。

一旦您开始在经理类中声明非静态会员变量,然后您将在Manager.log()中使用它们,而它不再是线程安全:然后可以通过多个线程访问相同的管理实例,一旦它们所有人都开始在同一成员变量中写作,您会遇到麻烦...

我希望这有点澄清。

最新更新