簡體   English   中英

同時用於多個請求的靜態成員和實例方法

[英]Static members and instance methods for multiple requests at the same time

如果我在類中將諸如記錄器對象之類的對象定義為靜態對象,請調用以下方法:

public class Manager
{    
    private static ClientLogManager log = new ClientLogManager();

    public void Log(string Message)
    {
         log.Debug(string Message);
    }
}

這是在類庫項目中定義的。

我的理解是,此應用程序的所有請求之間共享靜態變量,因此日志對象是共享的。 但是,方法Debug本身不是靜態的,但是對象是靜態的,因此該方法只有一個實例。 那是對的嗎?

如果很多用戶同時調用此代碼,則同時有2個請求正在調用log.Debug方法,那么第二個請求的消息是否可以覆蓋第一個請求的消息?

另外,用Singleton代替它會更好嗎? 每個請求不是一個Singleton對象嗎?

這是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個靜態成員實例。

“但是,Debug方法本身不是靜態的,但是對象是靜態的,因此該方法只有一個實例。對嗎?” 該聲明本身是正確的,但是...

歸結為:

  • 靜態方法和實例方法在內存中僅“存在”一次,不同之處在於,靜態方法不需要聲明它的類的實例即可執行,而實例方法則需要。

  • 如果可以同時處理多個請求,則必須在不同的線程上執行它們。 每個線程都有自己的調用堆棧,並且如果您使用線程執行方法調用,則傳遞給該方法的參數將放在該線程的調用堆棧中。

  • 這意味着,只要參數是值類型(如int)或不可變類型(如本例中的字符串),它就不能被另一個線程修改(因為它在另一個線程中不可見) ,或不可修改)。 因此,您不必擔心消息在Manager.Log()或ClientLogManager.Debug()方法中混雜在一起。

因此,當前的Manager和ClientLogManager實現都是線程安全的(至少,如果_log實例是線程安全的)。

一旦開始在Manager類中聲明非靜態成員變量,並打算在Manager.Log()中使用它們,那么它就不再是線程安全的:同一個Manager實例可以被多個線程訪問,並且一旦它們都開始在同一個成員變量中寫入,您就會遇到麻煩...

我希望這可以澄清一些事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM