单例模式与方法的同步异步
项目功能需求:
添加一个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(...))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)