C# lock 学习
从MSDN上看的例子,加上从网上看到的对于lock的一些解释,自己加以总结注释,记录一下。
先看代码:
class Program { static void Main(string[] args) { //实例化线程数组 Thread[] threads = new Thread[10]; //实例化Account对象 Account acc = new Account(1000); //构建十个线程赋值到threads for(int i=0;i<10;i++) { Thread t=new Thread(new ThreadStart(acc.DoTransactions)); threads[i]=t; } //执行线程 for (int i = 0; i < 10; i++) { threads[i].Start(); } Console.ReadKey(); } } class Account { //一个只读的Object对象实例,用来锁定 private readonly Object thisLock = new Object(); //用来在构建构造函数时赋值的 金额 int balance; //随即对象 Random r = new Random(); /// <summary> /// 构造函数 /// </summary> /// <param name="initial"></param> public Account(int initial) { balance = initial; } /// <summary> /// 减金额 /// </summary> /// <param name="amount">要减去的金额</param> /// <returns>返回 减去后的金额</returns> int Withdraw(int amount) { if (balance < 0) throw new Exception("Negative Balance"); //lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。 //这里将 只读的Object对象实例thisLock锁定 lock (thisLock) { //要减去的金额大于 账号上的金额 if (balance >= amount) { Console.WriteLine("Balance before Withdrawal :{0}", balance); Console.WriteLine("Amount to Withdraw : -{0}", amount); balance = balance - amount; Console.WriteLine("Balance after Withdrawal :{0}", balance); Console.WriteLine(" "); return amount; } else { return 0; } } } /// <summary> /// 随即获取1-100的值 传给Withdraw()方法 /// </summary> public void DoTransactions() { for (int i = 0; i < 100; i++) { Withdraw(r.Next(1, 100)); } } }
MSDN中对于lock的解释:lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
本例中使用了只读的Object对象实例thisLock来执行锁定。比如线程a执行到了lock(thisLock),判断thisLock是否被锁定,得知未被锁定,a锁定thisLock,执行”{}“内的语句。b此时也执行到了这里,得知thisLock已经被锁定了(a正在锁定中),b就等待,直到a执行完,b在执行lock。
MSDN中讲到lock(this)、lock(type(MyType))、lock(“myLock”)时是会有问题的,现在来说下为什么会有问题。
lock(this):如果实例可以被公共访问,则出现问题。这里会有两个问题:1>实例可被公共访问时,这里的锁定会导致其他访问不可用。2>这种锁定只能锁定当前实例,对其他实例没用。
lock(type(MyType)):这种锁定解决了上述情况的第二种问题,但是他出现第一种问题的可能性更大了。
lock(“myLock”):程序中任何使用“myLock”字符串的地方都会共享这个锁定。
综上所述,MSDN中给出的最佳做法是“定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。”
所以最佳办法是用 private static readonly Object lockThis=new Object();来锁定。
private:避免其他地方使用。
static:可以锁定到所有实例。
readonly:保证锁定的对象不被修改,否则后面的线程会畅通无阻了。