public class Logger { // 用於存放寫日誌任務的隊列 private Queue<Action> _queue; // 用於寫日誌的線程 private Thread _loggingThread; // 用於通知是否有新日誌要寫的「信號器」 private ManualResetEvent _hasNew; // 構造函數,初始化。 private Logger() { _queue = new Queue<Action>(); _hasNew = new ManualResetEvent(false); _loggingThread = new Thread(Process); _loggingThread.IsBackground = true; _loggingThread.Start(); } // 使用單例模式,保持一個Logger對象 private static readonly Logger _logger = new Logger(); private static Logger GetInstance() { /* 不安全代碼 lock (locker) { if (_logger == null) { _logger = new Logger(); } }*/ return _logger; } // 處理隊列中的任務 private void Process() { while (true) { // 等待接收信號,阻塞線程。 _hasNew.WaitOne(); // 接收到信號後,重置「信號器」,信號關閉。 _hasNew.Reset(); // 因爲隊列中的任務可能在極速地增長,這裏等待是爲了一次能處理更多的任務,減小對隊列的頻繁「進出」操做。 Thread.Sleep(100); // 開始執行隊列中的任務。 // 因爲執行過程當中還可能會有新的任務,因此不能直接對原來的 _queue 進行操做, // 先將_queue中的任務複製一份後將其清空,而後對這份拷貝進行操做。 Queue<Action> queueCopy; lock (_queue) { queueCopy = new Queue<Action>(_queue); _queue.Clear(); } foreach (var action in queueCopy) { action(); } } } private void WriteLog(string content) { lock (_queue) { // todo: 這裏存在線程安全問題,可能會發生阻塞。 // 將任務加到隊列 _queue.Enqueue(() => File.AppendAllText("log.txt", content)); } // 打開「信號」 _hasNew.Set(); } // 公開一個Write方法供外部調用 public static void Write(string content) { // WriteLog 方法只是向隊列中添加任務,執行時間極短,因此使用Task.Run。 Task.Run(() => GetInstance().WriteLog(content)); } }