lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。 ThreadInterruptedException 引发,如果 Interrupt 中断等待输入 lock 语句的线程。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。
常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
在 lock 语句的正文不能使用 等待 关键字
1、lock的是引用类型的对象,string类型除外。
2、lock推荐的做法是使用静态的、只读的、私有的对象。
3、保证lock的对象在外部无法修改才有意义,如果lock的对象在外部改变了,对其他线程就会畅通无阻,失去了lock的意义。
1 using System; 2 using System.Threading; 3 4 namespace Chapter1.Recipe9 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 Console.WriteLine("Incorrect counter"); 11 12 var c = new Counter(); 13 14 var t1 = new Thread(() => TestCounter(c)); 15 var t2 = new Thread(() => TestCounter(c)); 16 var t3 = new Thread(() => TestCounter(c)); 17 t1.Start(); 18 t2.Start(); 19 t3.Start(); 20 t1.Join(); 21 t2.Join(); 22 t3.Join(); 23 24 Console.WriteLine("Total count: {0}", c.Count); 25 Console.WriteLine("--------------------------"); 26 Console.ReadKey(); 27 Console.WriteLine("Correct counter"); 28 29 var c1 = new CounterWithLock(); 30 31 t1 = new Thread(() => TestCounter(c1)); 32 t2 = new Thread(() => TestCounter(c1)); 33 t3 = new Thread(() => TestCounter(c1)); 34 t1.Start(); 35 t2.Start(); 36 t3.Start(); 37 t1.Join(); 38 t2.Join(); 39 t3.Join(); 40 Console.WriteLine("Total count: {0}", c1.Count); 41 Console.ReadKey(); 42 } 43 44 static void TestCounter(CounterBase c) 45 { 46 for (int i = 0; i < 100000; i++) 47 { 48 c.Increment(); 49 c.Decrement(); 50 } 51 } 52 53 class Counter : CounterBase 54 { 55 public int Count { get; private set; } 56 57 public override void Increment() 58 { 59 Count++; 60 } 61 62 public override void Decrement() 63 { 64 Count--; 65 } 66 } 67 68 class CounterWithLock : CounterBase 69 { 70 private static readonly object _syncRoot = new Object(); 71 72 public int Count { get; private set; } 73 74 public override void Increment() 75 { 76 lock (_syncRoot) 77 { 78 Count++; 79 } 80 } 81 82 public override void Decrement() 83 { 84 lock (_syncRoot) 85 { 86 Count--; 87 } 88 } 89 } 90 91 abstract class CounterBase 92 { 93 public abstract void Increment(); 94 95 public abstract void Decrement(); 96 } 97 } 98 }