有时候在编写线程并发的时候需要考虑异步和同步的问题。有些资源只能是一个线程访问,其他的线程在这个线程没有释放资源前不能访问。类似于操作系统中临界资源的访问。C#Lock包裹的代码块具有原子操作的特性(要么执行到结束为止,要么不执行)。
举个列子:银行账户的余额就是典型的临界资源的问题,假如原本有1000,你的情妇A,B先后打500给你。A打500的这个操作是一个线程,从数据库取出余额的值累加正准备写回数据库的时候,由于某种原因(时间片用完、来了更高的优先级的线程)阻塞,这时候B又给你打500,他得到余额依然是1000,累加后写回数据库1500到手。这时刚才被阻塞的线程又获得执行权,将1500写回数据库。你莫名奇妙少了500,回去找情妇理论是没有结果的,银行系统的锅。
Lock可以运用在单列模式上。刚开始我一直纳闷Lock括号里面究竟写什么,经同学指点。大概是任意不会改变的对象(里面写一个固定的字符串”999“也可以)
那个对象是一把锁。它会把钥匙给第一个访问它的进程,如果进程完事就上交钥匙。有且只有一把钥匙,实现了原子操作
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TestLock { class TestThread { private static TestThread instance; private static Object obj = new object(); private TestThread() { } public static void GetInstance() { if (instance == null)//先判断,异步 { lock (obj)//任意不改变对象 { if (instance == null)//同步 { Console.WriteLine("初始化"); instance = new TestThread(); } } } } } }
Thread t1 = new Thread(TestThread.GetInstance); Thread t2 = new Thread(TestThread.GetInstance); Thread t3 = new Thread(TestThread.GetInstance); t1.Start(); t2.Start(); t3.Start();
结果是只打印一行初始化,如果没有lock包裹那块代码那么结果会有三行初始化。因为,线程都会遇到if (instance == null)真