一直以来对于lock关键字的用法都存有疑惑,也从网上看到很多关于他的资料包括MSDN,无奈MSDN讲述的真是让人上火。今天决定小小研究一下

一直都知道lock是锁定某一变量从而实现对某一代码段的独占执行。

但是对于lock(this)、lock(typeof(类名))、lock(字符串)、lock(公有变量) lock(私有变量) 有什么不同 却很是模糊

我假定了这样一种场景:某个时刻,只允许一个客户在打电话

定义一个客户类

代码1:(lock(this))

///定义一个Custmer类,要求某一时间,只允许一个客户在打电话
public class Custmer
{
public Custmer()
{
}
public Custmer(string name)
{
_name = name;
}
///某一时刻只允许一个客户在打电话
public void getPhone()
{
lock (this)
{ for (int i = 0; i < 10; i++)
{
Console.WriteLine(Thread.CurrentThread.Name+"正在跟客户在通话");
Thread.Sleep(1000);
} }
}
}

在主函数中调用,先实例化一个Custmer 实例

static void Main(string[] args)
{
Custmer c=new Custmer();
Thread t1 = new Thread(new ThreadStart(c.getPhone));
t1.Name = "t1";
Thread t2 = new Thread(new ThreadStart(c.getPhone));
t2.Name = "t2";
t1.Start(); t2.Start();
Console.Read(); }

可以预先分析一下结果,因为用的是lock(this),而this这时候代表的是实例c,当其中一个线程在使用的时候,另一个线程是不能使用的。也就是说,结果应该是其中一个线程先使用,另一个再使用,而不是交替使用。

运行结果1:

跟预想的结果一样,但是如果是多个客户实例呢,结果有怎样

代码2:

代码

static void Main(string[] args)
{
//这里我实例化了两个客户类
Custmer c=new Custmer();
Custmer c2 = new Custmer(); //线程1去接通c的电话
Thread t1 = new Thread(new ThreadStart(c.getPhone));
t1.Name = "t1";
//线程2去接通c2的电话
Thread t2 = new Thread(new ThreadStart(c2.getPhone));
t2.Name = "t2";
t1.Start(); t2.Start();
Console.Read(); }

再预想一下结果,对于线程t1,跟客户c接通电话,此时lock(this)中的this是当前实例c。同理,对于线程t2,this是实例c2.这样lock(this)锁定的是不同的对象,所以无法达到某一时刻,只有一个客户在电话。也就是说,两个线程会交替执行。

执行结果2:

与预想结果一样。从这里我们知道,lock(this)存在多个实例间互斥不能实现的问题,原因在于this指向的是不同的实例

另外在有的地方说lock(this)可能会造成死锁,所谓的死锁,无非就是一个线程长期锁定this不释放。 可能是lock锁定的代码段是个死循环,也可能你在一个死循环里调用lock锁定的代码段。总之是没有释放锁定对象。

Lock(typeof(类名))

我重新定义了一个sales类,用来在Customer类中锁定它

sales类

public class sales
{
public sales(string name)
{
_name = name;
}
string _name; public string Name
{
get { return _name; }
set { _name = value; }
} }

Customer类改写如下:

public class Custmer
{
public Custmer()
{
}
public Custmer(string name)
{
_name = name;
}
string _name; public string Name
{
get { return _name; }
set { _name = value; }
} public void getPhone()
{
lock (typeof(sales))//关键是这里
{ for (int i = 0; i < 10; i++)
{
Console.WriteLine(Thread.CurrentThread.Name+"正在跟客户在通话");
Thread.Sleep(1000);
} }
}
}

我们在主函数中,调用如Lock(this)的单个实例的情况,我们会发现,实现了互斥。多个实例的情况也实现了互斥。但是又有了新的问题。因为我们锁定的是类本身,所以如果有一个地方是在使用类,那么其他地方就不能使用该类,这样的限制过于苛刻。

3.Lock(字符串)

这个就更好玩了,他是实现了绝对的互斥。只要字符串内容相同,就能引起程序挂起。原因是在.NET中,字符串会被暂时存放,如果两个变量的字符串内容相同的话,.NET会把暂存的字符串对象分配给该变量。所以如果有两个地方都在使用lock(字符串)的话,它们实际锁住的是同一个对象。

那我们看一下代码和执行结果

代码:

public class Custmer
{
string flag = "ATually";//定义了一个字符串变量
public Custmer()
{
}
public Custmer(string name)
{
_name = name;
} string _name; public string Name
{
get { return _name; }
set { _name = value; }
} public void getPhone()
{
lock (flag)//关键是这里
{ for (int i = 0; i < 10; i++)
{
Console.WriteLine(Thread.CurrentThread.Name+"正在跟客户在通话");
Thread.Sleep(1000);
} }
}
}

多个实例的情况下的执行结果也实现了互斥。

对于Lock(共有变量)和Lock(私有变量)基本效果都一样,但是都会出现对于多个实例都无法实现互斥。

因此,微软推荐使用私有静态变量作为锁定的变量。但是个人觉得与锁定类和锁定字符串 没有什么不同。

以上只是个人浅见,如有错的地方,请不吝赐教,谢谢。

出处:http://www.csharpwin.com/csharpspace/12362r6119.shtml

lock关键字的用法的更多相关文章

  1. c#多线程中Lock()关键字的用法小结

    本篇文章主要是对c#多线程中Lock()关键字的用法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助     本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段 ...

  2. 锁·——lock关键字详解

    作  者:刘铁猛 日  期:2005-12-25 关键字:lock 多线程 同步 小序 锁者,lock关键字也.市面上的书虽然多,但仔细介绍这个keyword的书太少了.MSDN里有,但所给的代码非常 ...

  3. C# lock 关键字的一些理解

    C# lock 关键字的一些理解 问题1:谁是锁? lock 这个关键字,并不是“锁”,真正的“锁”是那个被lock的Object类型的“对象”,请注意,这里为“对象”加了双引号着重强调被lock的是 ...

  4. lock关键字的使用

    最近在代码中,发现别人使用了lock关键字,为了理解别人写的代码,所以自己对lock关键字的使用研究了下. 微软官方解释,请百度:lock 语句(C# 参考) 微软给了个官网实例代码: class A ...

  5. [转载]C#中as和is关键字的用法

    这篇文章主要介绍了C#中as和is关键字的用法的相关资料,需要的朋友可以参考下. 原文链接:http://www.jb51.net/article/80944.htm#comments  在程序中,进 ...

  6. C++中typename关键字的用法

    我在我的 薛途的博客 上发表了新的文章,欢迎各位批评指正. C++中typename关键字的用法

  7. java中synchronized关键字的用法

    在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...

  8. lock关键字只不过是C#提供的语法糖

    lock关键字只不过是C#提供的语法糖, 最终使用的还是Monitor类. Monitor类的Enter方法要求传入的参数不为null, 否则会有ArgumentNullException excep ...

  9. C#的lock关键字

    using System; using System.Threading; namespace Test { class Program { //一.Lock定义 //lock 关键字可以用来确保代码 ...

随机推荐

  1. echarts使用要点

  2. Laravel5.1 模型 --远层一对多关系

    远层一对多我们可以通过一个例子来充分的了解它: 每一篇文章都肯定有并且只有一个发布者 发布者可以有多篇文章,这是一个一对多的关系.一个发布者可以来自于一个国家 但是一个国家可以有多个发布者,这又是一个 ...

  3. Cocos2d-x 3.3Bate0 ExpandedListView

    之前写的ExpandedListView版本号因为版本号升级这里提供Cocos2d-x 3.3Bate0 版本号 代码下载:http://download.csdn.net/detail/qqmcy/ ...

  4. 《ASP.NET1200例》C#在网页上编写动态时钟

    包含Timer类的命名空间有3个 Timer Class (System.Threading)‎ Timer Class (System.Windows.Forms)‎ 一般用于窗体程序 Timer  ...

  5. android应用安全——数据安全

    数据安全包含数据库数据安全.SD卡数据(外部存储)安全.RAM数据(内部存储)安全. android中操作数据库可使用SQLiteOpenHelper或ContentProvider的方式.使用SQL ...

  6. (转)HTTP

    HTTP(Hyper Text Transfer Protocol)超文本传输协,是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型. HTTP特点: 支持客户 / 服务器模式 简单快速 ...

  7. JAVA源码之JDK(一)——java.lang.Object

    想要深入学习JAVA,还需追本溯源,从源码学起.这是我目前的想法.如今JAVA各种开源框架涌出,很多JAVA程序员都只停留在如何熟练使用的层次.身为其中一员的我深感惭愧,所以要加快学习的脚步,开始研究 ...

  8. windows程序查看可以行文件依赖库

    通常在做windows下开发程序,发布的时候需要同时打包一些依赖库:我们可以通过工具直接查看需要发布的程序依赖的程序,这样可以方便快捷的打包程序 这里我们推荐使用:dependencywalker 下 ...

  9. 修改SQL Server 数据库的编码

    ALTER DATABASE [dbnam] collate SQL_Latin1_General_CP1_CI_AS 查询编码号:SELECT COLLATIONPROPERTY('SQL_Lati ...

  10. 微信公众号开发 但是服务端仅仅接收到了 p1 p2 没有接收到p3

    w 栗子 js window.location = www.xx.com?p1=123&p2=456&p3=789 但是服务端仅仅接收到了 p1 p2 没有接收到p3 原因有哪些呢? ...