线程学习7——lock语句
2011-06-03 10:46
225 查看
什么是lock语句?
lock语句是设置锁定和解除锁定的一种简单方式。
为什么使用lock语句?
在使用多线程的过程中,会出现很多难以发现的问题,比如竞态条件与死锁,为了避免这些同步问题,所以使用lock语句,当然这并不是解决同步问题的唯一方法。
lock语句的作用:
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock语句的用法:
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。 此语句的形式如下:
lock语句的注意事项:
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。 常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
第一种情况:
1.同一个对象,不同线程。lock (this) 不会出现问题的例子
[/b] 2.不同对象,不同线程。lock (this) 会出现问题的例子
[/b]
第二种情况:如果一个类是公有的时,应该避免在基方法或属性中使用lock(this)语句,因为如果有其他人使用你的组件,
它并不了解你的组件内部是否使用了锁,当组件内部使用了锁,而使用者又在类外部对类实例尝试加锁,则可能导致一个死锁。
例如:
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
例如:
string a = "String Example";
string b = "String Example";
string c = (new StringBuilder()).Append("String Example").ToString();
Console.WriteLine("a==b? {0}", object.ReferenceEquals(a, b));
Console.WriteLine("a==c? {0}", object.ReferenceEquals(a, c));
上面程序执行的结果是:
a==b? True
a==c? False
从上面可以看出,a和b指向的是同一个引用,而lock正是通过引用来区分并加锁临界代码段的。也就是说,如果在我们一程序的一个部分中使用了
lock("thisLock")进行加锁,而在程序的另一个位置同样也使用lock("thisLock")进行加锁,则极有可能导致一个死锁,因而是很危险的。实际上,不只是lock("thisLock")这样的语句,在lock中使用string类型的引用都有可能导致死锁。
lock语句是设置锁定和解除锁定的一种简单方式。
为什么使用lock语句?
在使用多线程的过程中,会出现很多难以发现的问题,比如竞态条件与死锁,为了避免这些同步问题,所以使用lock语句,当然这并不是解决同步问题的唯一方法。
lock语句的作用:
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock语句的用法:
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。 此语句的形式如下:
Object thisLock = new Object(); lock (thisLock) { // Critical code section. }
lock语句的注意事项:
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。 常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
第一种情况:
1.同一个对象,不同线程。lock (this) 不会出现问题的例子
[b]classMyMainClass { privatestaticreadonlyobject lockHelper =newobject(); privatestaticint num =0; //记录不同线程操作的次数privateint count =0; //记录每个对象执行次数staticvoid Main() { //一个对象 MyMainClass c1 =new MyMainClass(); //两个线程 Thread myThread1 =new Thread(new ThreadStart(c1.DoSomething)); myThread1.Name ="FirstThread"; myThread1.Start(); Thread myThread2 =new Thread(new ThreadStart(c1.DoSomething)); myThread2.Name ="SecondThread"; myThread2.Start(); Console.WriteLine("C1 count: {0}", c1.count); Console.ReadLine(); } publicvoid DoSomething() { //此处可以用this,或者也可以用lockHelperlock (this) { while (num <100) { num++; Console.WriteLine("{0} add value: {1}", Thread.CurrentThread.Name, num); count++; } } } }
[/b] 2.不同对象,不同线程。lock (this) 会出现问题的例子
[b]classMyMainClass { privatestaticreadonlyobject lockHelper =newobject(); privatestaticint num =0; //记录不同线程操作的次数privateint count =0; //记录每个对象执行次数staticvoid Main() { //两个对象 MyMainClass c1 =new MyMainClass(); MyMainClass c2 =new MyMainClass(); //两个线程 Thread myThread1 =new Thread(new ThreadStart(c1.DoSomething)); myThread1.Name ="FirstThread"; myThread1.Start(); Thread myThread2 =new Thread(new ThreadStart(c2.DoSomething)); myThread2.Name ="SecondThread"; myThread2.Start(); Console.WriteLine("C1 count: {0}", c1.count); Console.WriteLine("C2 count: {0}", c2.count); Console.ReadLine(); } publicvoid DoSomething() { //lock (this) //此处只可以用lockHelper,若用this则锁不住lock (lockHelper) { while (num <100) { num++; Console.WriteLine("{0} add value: {1}", Thread.CurrentThread.Name, num); count++; } } } }
[/b]
第二种情况:如果一个类是公有的时,应该避免在基方法或属性中使用lock(this)语句,因为如果有其他人使用你的组件,
它并不了解你的组件内部是否使用了锁,当组件内部使用了锁,而使用者又在类外部对类实例尝试加锁,则可能导致一个死锁。
例如:
public class InternalClass { ..... private void ThreadFunction() { ...... lock (this) { ...... } } } public class ClassMain { private InternalClass theClass = new InternalClass(); public ClassMain() { lock (theClass) // 如果注释掉这句,ThreadFunction()中的lock将执行成功 { Console.WriteLine("对象被锁定, 在这里我们获得了一个死锁..."); } } } static void Main(string[] args) { ClassMain cm = new ClassMain(); Console.WriteLine("Press Enter to exit"); Console.ReadLine(); } 因此,应尽量避免甚至拒绝使用lock(this)这样的语句。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
lock (typeof (MyType)) Type t1 = typeof(MyType), Type t2 = typeof(MyType), 这样的两个t1,t2,引用是相等的,跟lock(this)会产生同样的问题.
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
例如:
string a = "String Example";
string b = "String Example";
string c = (new StringBuilder()).Append("String Example").ToString();
Console.WriteLine("a==b? {0}", object.ReferenceEquals(a, b));
Console.WriteLine("a==c? {0}", object.ReferenceEquals(a, c));
上面程序执行的结果是:
a==b? True
a==c? False
从上面可以看出,a和b指向的是同一个引用,而lock正是通过引用来区分并加锁临界代码段的。也就是说,如果在我们一程序的一个部分中使用了
lock("thisLock")进行加锁,而在程序的另一个位置同样也使用lock("thisLock")进行加锁,则极有可能导致一个死锁,因而是很危险的。实际上,不只是lock("thisLock")这样的语句,在lock中使用string类型的引用都有可能导致死锁。
相关文章推荐
- 线程学习7——lock语句
- C#多线程开发6:使用lock语句同步多个线程
- C#多线程开发:使用lock语句同步多个线程
- 线程关于wait,notify,notifyAll及Lock的学习(买卖)
- Java线程学习笔记之Lock
- 线程学习二,ReentrantLock.Lock实现线程互斥
- java 多线程学习之多生产者多消费者产生的线程安全问题分析与解决:Lock和Condition
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
- C++学习笔记6 - 分支语句和逻辑运算符
- oraclel数据库中的SQL语句使用学习
- Shell 学习15 - Shell if else 语句
- 慕课学习C笔记01-第1~4章数据类型、运算符和程序结构语句
- java多线程之路之线程状态—Core Java学习
- 线程学习10——BackgroundWorker类
- javascript学习笔记(4)--with和for(in)对象语句
- Java显式锁学习总结之四:ReentrantLock源码分析
- Leetcode算法学习日志-752 Open the Lock
- JAVA学习日志(11-1-线程及多线程概述)
- Python学习之字典与控制语句
- aauto学习系列之<7>控制语句2