C#中的lock关键字有何作用
作为C#的程序员来说,在遇到线程同步的需求时最常用的就是lock关键字。但如何正确并有效地使用lock,却是能否高效地达到同步要求的关键。正因为如此,程序员需要完全理解lock究竟为程序做了什么。
所涉及的知识点
• lock的等效代码
• System.Threading.Monitor类型的作用和使用方法
分析问题
1.lock的等效代码
在.NET的多线程程序中,经常会遇到lock关键字来控制同步,比如下列代码:
private object o = new object();
public void Work()
{
lock(o)
{
//做一些需要线程同步的工作
}
}
事实上,lock这个关键字是C#为方便程序员而定义的语法,它等效于安全地使用System.Threading.Monitor类型。上面的代码就直接等效于下面的代码:
private object o = new object();
public void Work()
{
//这里很重要,是为了避免直接使用私有成员o,而导致线程不安全
object temp = o;
System.Threading.Monitor.Enter(temp);
try
{
//做一些需要线程同步的工作
}
finally
{
System.Threading.Monitor.Exit(temp);
}
}
正如你看到的,真正实现了线程同步功能的,就是System.Threading.Monitor类型,lock关键字只是用来代替调用Enter、Exit方法,并且将所有的工作包含在try块内,以保证其最终退出同步。
2.System.Threading.Monitor类型的作用和使用
在前文中已经提到了,Monitor类型的Enter和Exit方法用来实现进入和退出对象的同步。具体来说,当Enter方法被调用时,对象的同步索引将被检查,并且.NET将负责一系列的后续工作,来保证对象访问时线程的同步,而Exit方法的调用,则保证了当前线程释放该对象的同步块。
示例
下列演示了自定义的类如何利用lock关键字(也就是Monitor类型)来实现线程同步,具体定义了一个包含需要同步执行方法的类型。
/// <summary>
/// 演示同步锁
/// </summary>
public class MyLock
{
//用来在静态方法中同步
private static object o1 = new object();
//用来在成员方法中不同
private object o2 = new object();
//成员变量
private static int i1 = 0;
private int i2 = 0;
/// <summary>
/// 测试静态方法的同步
/// </summary>
/// <param name=" handleObject ">同步时操作的对象</param>
public static void Increment1(object handleObject)
{
lock (o1)
{
Console.WriteLine("i1的值为:{0}", i1);
//这里刻意制造线程并行机会,来检查同步的功能
Thread.Sleep(200);
i1++;
Console.WriteLine("i1自增后为:{0}", i1);
}
}
/// <summary>
/// 测试成员方法的同步
/// </summary>
/// <param name=" handleObject ">同步时操作的对象</param>
public void Increment2(object handleObject)
{
lock (o2)
{
Console.WriteLine("i2的值为:{0}", i2);
//这里刻意制造线程并行机会,来检查同步的功能
Thread.Sleep(200);
i2++;
Console.WriteLine("i2自增后为:{0}", i2);
}
}
}
这样在main方法中,调用该类型对象的方法和其静态方法,测试其同步的效果。代码如下
/// <summary>
/// 程序入口
/// </summary>
class Program
{
/// <summary>
/// 测试同步效果
/// </summary>
static void Main(string[] args)
{
//开始多线程
Console.WriteLine("开始测试静态方法的同步");
for (int i = 0; i < 5; i++)
{
Task t = new Task(MyLock.Increment1, i);
t.Start();
}
//这里等待线程执行结束
Thread.Sleep(3 * 1000);
Console.WriteLine("开始测试成员方法的同步");
MyLock myLock = new MyLock();
//开始多线程
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(myLock.Increment2);
t.Start();
}
Console.Read();
}
}
下面是程序的执行结果:
开始测试静态方法的同步
i1的值为:0
i1自增后为:1
i1的值为:1
i1自增后为:2
i1的值为:2
i1自增后为:3
i1的值为:3
i1自增后为:4
i1的值为:4
i1自增后为:5
开始测试成员方法的同步
i2的值为:0
i2自增后为:1
i2的值为:1
i2自增后为:2
i2的值为:2
i2自增后为:3
i2的值为:3
i2自增后为:4
i2的值为:4
i2自增后为:5
总结
可以看到,线程同步被很好地保证了。这里需要强调的是,线程同步本身违反了多线程并行运行的原则,所以读者在使用线程同步时应该尽量做到把lock加在最小的程序块上。如果一个方法有大量的代码需要线程同步,那就需要重新考虑程序的设计了,是否真的有必要进行多线程处理,毕竟线程本身的开销也是相当大的。
对静态方法的同步,一般采用静态私有的引用成员,而对成员方法的同步,一般采用私有的引用成员。读者需要注意静态和非静态成员的使用,都把同步对象申明为私有,这是保证线程同步高效并且正确的关键点。
说明:以上内容是根据网上内容进行整理。
C#中的lock关键字有何作用的更多相关文章
- C#中的lock关键字;就是lock住一个大家都共同访问的(静态static的)东东就行了
public class ChatService : IChat //继承IChat接口或者说IChat的实现类 { //定义一个静态对象用于线程部份代码块的锁定,用于lock操作 private s ...
- C#中的lock关键字
前几天与同事激烈讨论了一下,有一点收获,记录起来. 首先给出MSDN的定义: lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.这是通过在代码块运行期间为给定对象获取互斥锁来实现的. ...
- C#中的lock关键字(初识)
http://kb.cnblogs.com/page/88513/ 首先给出MSDN的定义: lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.这是通过在代码块运行期间为给定对象获取互 ...
- (转载)C#中的lock关键字
lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.这是通过在代码块运行期间为给定对象获取互斥锁来实现的. 先来看看执行过程,代码示例如下: 假设线程A先执行,线程B稍微慢一点.线程A执 ...
- java中的this关键字三种作用
1.表示类中的属性和调用方法2.调用本类中的构造方法3.表示当前对象
- java中关键字volatile的作用
用在多线程,同步变量. 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况.volatile就是用来 ...
- C#中Monitor类、Lock关键字和Mutex类
线程:线程是进程的独立执行单元,每一个进程都有一个主线程,除了主线程可以包含其他的线程.多线程的意义:多线程有助于改善程序的总体响应性,提高CPU的效率.多线程的应用程序域是相当不稳定的,因为多个线程 ...
- 转!!java中关键字volatile的作用
用在多线程,同步变量. 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况.volatile就是用来 ...
- C++中关键字explicit的作用
C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色. 1 是个构造器 ,2 是个默认且隐含的类型转换操作符. 所以, 有时候在我们写下如 AAA ...
随机推荐
- Microsoft.CSharp.CSharpCodeProvider
Microsoft.CSharp.CSharpCodeProvider MSDN 提供对 C# 代码生成器和代码编译器的实例的访问.类提供可用来检索 C# ICodeGenerator 和 ICode ...
- 机器学习(Machine Learning)&深度学习(Deep Learning)资料
<Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost到随机森林.D ...
- Java的wait(), notify()和notifyAll()使用小结
wait(),notify()和notifyAll()都是java.lang.Object的方法: wait(): Causes the current thread to wait until an ...
- Binary Tree Postorder Traversal--leetcode难题讲解系列
https://leetcode.com/problems/binary-tree-postorder-traversal/ Given a binary tree, return the posto ...
- vs.net 2005 C# WinForm GroupBOX 的BUG?尝试读取或写入受保护的内存。这通常指示其他内存已损坏
其实很久没有写程序了,国庆难得有空闲,写了个游戏辅助机器人,程序写好能用后本想把UI控件放到GroupBox里归下分类,美化下界面,结果一运行报“尝试读取或写入受保护的内存.这通常指示其他内存已损坏” ...
- CORS Cookie,和nodejs中的具体实现
CORS(跨来源资源共享协议),高级浏览器(Chrome,firefox, opera, safir, ie10)在 XMLHttpRequest(AJAX) 中已经支持了这个协议.可以实现ajax跨 ...
- What's New in iOS9 iOS9功能改进
What's New in iOS9 This article summarizes the key developer-related features introduced in iOS 9, w ...
- PLSQL Developer 出64位版了
在win64环境上,一般安装oracle客户端都是64位的了,Toad 也是64位的,但是PLSQL Developer 还是32位的,只能单单为它装一个32位的oracle 客户端,现在退出64位, ...
- 二十二、【轻量级开源框架】EFW框架Web前端开发之JqueryEasyUI
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...
- 解决访问StackOverFlow太慢的问题
Stackoverflow加载时访问了被屏蔽的站点ajax.googleapis.com,导致加载缓慢,把这个站点加到Hosts里,指向127.0.0.1即可