《单例模式》你需要注意的问题
单例模式大家都很熟悉,但是使用过程中,稍微不注意就会出现大问题。
单例模式:该类在整个系统生命周期中有且只有一个实例。
单例的创建:
注意问题:
- 构造函数 私有化 :保证 实例化该类通过统一的接口
- 提供一个统一的接口获取类的实例
- 保证线程同步
例如:
public class CommonQuery
{
private CommonQuery() { }
object aLocker = new object();
static readonly CommonQuery _cmQuery = null;
public static CommonQuery GetCommonQuery()
{
lock(aLocker)
{
if(_cmQuery==null)
{
_cmQuery = new CommonQuery();
}
}
}
{
private CommonQuery() { }
object aLocker = new object();
static readonly CommonQuery _cmQuery = null;
public static CommonQuery GetCommonQuery()
{
if(_cmQuery!=null)
{return _cmQuery;}lock(aLocker)
{
if(_cmQuery==null)
{
_cmQuery = new CommonQuery();
}
}
return _cmQuery;
}}
单例中应该避免的问题:
- 避免无限递归调用
- 尽量少将数据或其他类的实例保存到该单例类中的全局变量中(如果有必要除外)
以上2点问题主要针对内存的问题,因为单例是在整个系统生命周期中都一直存在,如果有大量信息被单例保存,可想而知,我们的内存伤不起啊,
导致的结果就是 内存溢出!
场景:
多任务定时采集某网站数据
该需求 核心我一般这么设计:至少2个类
- CommonQuery:单例,负责 采集任务初始化、线程控制、具体采集任务调度、采集结果/错误等后续处理、通知前端UI
- WebWorker:非单例,负责具体采集任务,执行结果将反馈给CommonQuery
核心序列图:
核心类图:
基本上核心 就是上面2个类,
执行流程是:在CommonQuery中的 Start()方法中,生成N个(根据多线程需要)webWorker对象,执行具体任务,当该任务执行完成或者出错以后,便通过事件EFinished或者EError来
通知CommonQuery,此时CommonQuery 根据实际情况来处理是继续新建任务来执行,还是判断整个任务结束,通知前台UI。(整个过程采用多线程异步)
注意点:
- 在CommonQuery中 不需要保存任何webworker实例!应该在Start()方法里面去new WebWorker对象
- 在WebWorker的EFinished/EError事件处理中(在CommonQuery中处理),千万别调用新的一轮采集任务的开始!(此时造成无限递归!灰常危险!!)
- 检查CommonQuery,尽量减少将变量保存下来
这几点主要针对内存的建议,一般这种采集任务执行时间都较长,有时候需要连续几天不停的采集,此时如果设计的有问题,出现以上3中情况,呵呵,您的内存伤不起啊。。。
C#技术交流: 64913828