前进中的蜗牛

番茄大叔

水滴穿石,非一日之功;没有量变,何来质变。

单例模式与方法的同步异步

项目功能需求:

添加一个log记录工具类,将每天的log信息分别记入新建的文本文件中。(要求自己写一个简单实现,不借助第三方类库)。
首先想法:应log工具类需要访问文本资源,将其设计为单例模式,以避免多线程访问同一资源报异常。

public class TextLogger
	{
		private static string _logPath = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, "Logs\\Log\\");
		
		private static TextLogger _instance = null;

		public static TextLogger Instance
		{
			get
			{
				if (_instance == null)
				{
					_instance = new TextLogger();
				}
				return _instance;
			}
		}

		private TextLogger()
		{
			if (!Directory.Exists(_logPath))
			{
				Directory.CreateDirectory(_logPath);
			}
		}

		public void WriteLog(string message)
		{
			try
			{
				using (StreamWriter sw = new StreamWriter(_logPath + DateTime.Today.ToString("yyyy-MM-dd") + ".log", true))
				{
					sw.WriteLine(DateTime.Now.ToString("HH:mm:ss.fffff") + "\t" + message);
				}
			}
			catch
			{
			}
		}
	}

使用TextLogger工具,TextLogger.Instance.WriteLog("Application_Start Begin");,在单线程下可以正常工作,但到了多线程下会偶然报bug,该怎么解决呀?

理清概念:

  • 单例模式:保证的是在多线程下,该类只存在唯一的对象(不能保证,对象的某个方法之被单线程调用)
  • 方法的同步异步:从概念上理解同步与异步与是否多线程没有关系,但在.net,异步的实现本质上是:执行耗时操作时,为消除当前线程的阻塞,开启新的线程执行其他任务。(所以在方法中保证同步执行需要加锁lock)

举个测试小栗子,在控制中新建

class SyncHelper
{
    public void Execute()
    {
        Console.WriteLine("Excute at {0}", DateTime.Now);
        Thread.Sleep(5000);
    }
} 

Main函数

  class Program
  {
      static void Main(string[] args)
      {
          SyncHelper helper = new SyncHelper();
          Timer timer = new Timer(
          delegate
          {
              helper.Execute();
          }, null, 0, 1000); 
   
          Console.Read(); 
   
      }
  } 

执行发现,每个1s打印异常而非5s。在Execute()方法上添加Attribute线程锁[MethodImpl(MethodImplOptions.Synchronized)]在执行发现输出将为5s。

  • [MethodImplAttribute(MethodImplOptions.Synchronized)]仍然采用加锁的机制实现线程的同步。
  • 如果[MethodImplAttribute(MethodImplOptions.Synchronized)]被应用到instance method,相当于对当前实例加锁。
  • 如果[MethodImplAttribute(MethodImplOptions.Synchronized)]被应用到static method,相当于当前类型加锁

结论

所以最简单的解决方法:在TextLogger.WriteLog方法上添加[MethodImpl(MethodImplOptions.Synchronized)]

参考自[MethodImpl(MethodImplOptions.Synchronized)]、lock(this)与lock(typeof(...))

posted @ 2019-01-21 18:20  LoveTomato  阅读(1037)  评论(0编辑  收藏  举报