刚才在看阿寻的博客”C#设计模式学习笔记-单例模式“时,发现了评论里有几个人在问单例模式在多线程环境下为什么lazy模式要加两个if进行判断,评论中的一个哥们剑过不留痕,给他们写了一个demo来告诉他们为什么。

我看了一下这个demo,确实说明了这个问题,但我认为不够直观,呵呵,于是我就稍微的改了一下。

这是剑过不留痕的demo

using System;
using System.Threading; namespace SingletonPattern
{
class Program
{
static Thread[] threads; static void Main(string[] args)
{
int threadsCapacity; Console.WriteLine("请输入开启的线程数:");
string s;
do
{
s = Console.ReadLine();
if (!int.TryParse(s, out threadsCapacity))
{
Console.WriteLine("数字格式不正确,请输入开启的线程数:");
continue;
}
else if ( > threadsCapacity)
{
Console.WriteLine("数字应不小于 1,请输入开启的线程数:");
continue;
}
else
{
break;
}
} while (true); threads = new Thread[threadsCapacity];
Program pg = new Program();
for (int i = ; i < threads.Length; i++)
{
Thread thread = new Thread(new ThreadStart(Singleton.GetIns));
thread.Name = "线程 " + i;
threads[i] = thread;
} for (int i = ; i < threads.Length; i++)
{
threads[i].Start();
} Console.ReadKey();
}
} class Singleton
{
private static Singleton instance;
private static object _lock = new object();
private static int instanceQuantity = ; private Singleton()
{ } public static Singleton GetInstance()
{
if (instance == null)
{
// 挂起线程,确保所有的线程都执行到这并等待
Thread.Sleep(); lock (_lock)
{
//if (instance == null)
//{
// instance = new Singleton();
// ++instanceQuantity;
// Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 实例!");
//} instance = new Singleton();
++instanceQuantity;
Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 实例!");
}
}
return instance;
} public static void GetIns()
{
GetInstance();
}
}
}

下面是我修改过得demo,修改的地方主要在GetInstance()这个方法内部,其他地方没动,所以我只贴出修改代码的地方,免得占空间!

public static Singleton GetInstance()
{
if (instance == null)
{
// 挂起线程,确保所有的线程都执行到这并等待
Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,instance等于null,哦,对象还没创建呢,看来我有机会哦!");
Thread.Sleep(); lock (_lock)
{
Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,instance等于null,哈哈,我锁,我是第一个到的!创建对象的任务就交给我了!");
if (instance == null)
{
instance = new Singleton();
++instanceQuantity;
Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,哼哼,对象是我创建的!");
}
else
{
Console.WriteLine("我是"+Thread.CurrentThread.Name + ",虽然我之前判断instance等于null,但现在判断的时候,却不等null了,唉,还是被别人快了一步!不过好在我判断了,要不就多创建了一个,失去了单例模式的意义!");
}
//Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 实例!");
//instance = new Singleton();
//++instanceQuantity;
//Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 实例!");
}
}
return instance;
}

下面是运行的结果,多运行几遍就可能出现这个结果了。

文字描述:

虽然线程0先进的第一个if,但创建对象的确实线程1,而此时,线程0已经判断了instance==null,所以他还会再创建一个对象,因为并没有人告诉线程0,线程1已经创建过对象了,而内部的这个if,就是为了告诉别人,对象我已经创建过了!其他人就不要再创建了,不知道我这样解释,清楚不!

单例模式在多线程环境下的lazy模式为什么要加两个if(instance==null)的更多相关文章

  1. 一个由单例模式在多线程环境下引发的 bug

    问题症状 HTTP 日志系统,老是出现日志信息覆盖的情况.比如同时调用 A 接口和 B 接口,B 接口请求响应信息变成了 A 接口请求响应相关信息.这个问题在并发量大的情况下越来越严重. 问题初步分析 ...

  2. Java指令重排序在多线程环境下的应对策略

    一.序言 指令重排在单线程环境下有利于提高程序的执行效率,不会对程序产生负面影响:在多线程环境下,指令重排会给程序带来意想不到的错误. 本文对多线程指令重排问题进行复原,并针对指令重排给出相应的解决方 ...

  3. SQLite在多线程环境下的应用

    文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...

  4. 多线程环境下非安全Dictionary引起的“已添加了具有相同键的项”问题

    问题: 代码是在多线程环境下,做了简单的Key是否存的判断, 测试代码如下: public class Program { static Dictionary<string, Logger> ...

  5. C#多线程环境下调用 HttpWebRequest 并发连接限制

    C#多线程环境下调用 HttpWebRequest 并发连接限制 .net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制,这个限制在桌面操作系统如 win ...

  6. C++多线程环境下的构造函数

    多线程的环境里,我们总不可避免要使用锁.于是一个常见的场景就是: class ObjectWithLock { private: std::mutex mtx_; SomeResType shared ...

  7. Asp.Net在多线程环境下的状态存储问题

    在应用开发中,我们经常需要设置一些上下文(Context)信息,这些上下文信息一般基于当前的会话(Session),比如当前登录用户的个人信息:或者基于当前方法调用栈,比如在同一个调用中涉及的多个层次 ...

  8. HttpClient在多线程环境下踩坑总结

    问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状态. 而且,从程序日志中判断有线程处于han ...

  9. 多线程环境下的UI异步操作

    转自原文 多线程环境下的UI异步操作 解决VS中,线程间不可互操作的问题,一揽子解决方案: 一.首先,定义一个类:SetControlProperty using System.Reflection; ...

随机推荐

  1. 类中的普通方法伪装成属性 @property

    class P: def __init__(self,name,age): self.name=name if type(age) is int: self.__age=age else: print ...

  2. JavaSE 学习笔记之正则表达式(二十五)

    正则表达式:其实是用来操作字符串的一些规则. 好处:正则的出现,对字符串的复杂操作变得更为简单. 特点:将对字符串操作的代码用一些符号来表示.只要使用了指定符号,就可以调用底层的代码对字符串进行操作. ...

  3. Leetcode 126.单词接龙II

    单词接龙II 给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列.转换需遵循如下规则: 每次转换只能 ...

  4. Bellman_ford 算法 Currency Exchange POJ1860

    Bellman_ford算法用于寻找正环或者负环! 算法导论: 24.1 The Bellman-Ford algorithm The Bellman-Ford algorithm solves th ...

  5. 洛谷—— P2196 挖地雷

    https://www.luogu.org/problem/show?pid=2196 题目背景 NOIp1996提高组第三题 题目描述 在一个地图上有N个地窖(N<=20),每个地窖中埋有一定 ...

  6. WPS for Linux字体配置(Ubuntu 16.04)

    错误提示: 解决方法: 从http://bbs.wps.cn/thread-22355435-1-1.html下载字体库,离线版本:(链接: https://pan.baidu.com/s/1i5dz ...

  7. mysql中有关树的函数

    用mysql客户端在库中建立函数queryOrgChildren(查找子节点)和queryOrgLevel(查看当前节点在树中的级别):DROP FUNCTION IF EXISTS `queryOr ...

  8. TCP/IP具体解释学习笔记--TCP的坚持和保活定时器

    TCP的坚持定时器 1.基本概念 TCP的接收方指名希望从发送方接收的数据字节(窗体大小)来进行流量控制,假设窗体大小为0.那么放送方就会阻止发送数据,直到接收方发来一个已跟新窗体大小的ACK为止,那 ...

  9. 适用于app.config与web.config的ConfigUtil读写工具类 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类) 基于ASP.NET WEB API实现分布式数据访问中间层(提供对数据库的CRUD) C# 实现AOP 的几种常见方式

    适用于app.config与web.config的ConfigUtil读写工具类   之前文章:<两种读写配置文件的方案(app.config与web.config通用)>,现在重新整理一 ...

  10. Linux VM环境配置

    1. 直接打 ifconfig ,显示 bash: ifconfig: command not found 打入全路径,查看IP     /sbin/ifconfig 2. 主机ping不通虚拟机, ...