当程序涉及高并发访问情况时,多线程编程就不得不考虑,今天简单说下我对lock机制的理解
1.c#中使用lock,是为了当前线程以独占的方式去访问某段代码(即lock{}里边的代码块),当代码段结束执行结束并退出后,其他线程才能进入这段代码,之所以要有这种控制,是为了状态的安全以及避免一些并发操作带来不可预知的后果
2.lock使用的对象:不能使用值类型如:int,bool
lock传入的对象需要时引用类型,如果传入值类型(如2),会造成装箱,这样的后果就是多次进入lock独占区多次装箱,每次lock的就是不同的对象,就无法起到lock的效果了,当然,也不能是string类型,这点MSDN有特别说明,记住便可
避免使用公共对象,及lock(this),因为其只对当前对象有效 ,如果多个对象就达不到同步的效果
自定义类推荐使用私有、只读、静态对象,如:private static readonly object obj = new object();
示例代码:
1 internal class Account 2 { 3 //用于判断状态的对象 4 private static readonly object obj = new object(); 5 6 Random rMoney = new Random(); 7 8 //银行账户 9 private decimal account; 10 11 internal Account(decimal account) 12 { 13 this.account = account; 14 } 15 16 /// <summary> 17 /// 取钱方法 18 /// </summary> 19 /// <param name="amount">用户要取的金额</param> 20 internal void AccessAccount(decimal amount) 21 { 22 if (amount <= 0) 23 { 24 throw new Exception("所取金额无效"); 25 } 26 27 lock (obj) 28 { 29 Console.WriteLine("当前访问线程:" + Thread.CurrentThread.Name); 30 //线程等待500ms:比如线程1执行进来后,500ms后线程2已经在等待了,造成效果就是:每个线程执行10次方法间隔会有其他线程进来 31 Thread.Sleep(500); 32 if (amount <= account) 33 { 34 account -= amount; 35 } 36 } 37 } 38 39 //测试提款方法 40 internal void Test() 41 { 42 //每个线程调用10次取款方法 43 for (int i = 0; i < 10; i++) 44 { 45 AccessAccount(rMoney.Next(0, 100)); 46 } 47 } 48 }
测试代码:
1 class Program 2 { 3 //定义多个线程 4 private static Thread[] threads = new Thread[10]; 5 6 static void Main(string[] args) 7 { 8 //初始账户1000元 9 Account account = new Account(1000); 10 11 //初始化线程 12 for (int i = 0; i < 10; i++) 13 { 14 //每个线程都附加取款方法 15 threads[i] = new Thread(account.Test); 16 } 17 //设置线程名称 18 for (int i = 0; i < 10; i++) 19 { 20 threads[i].Name = i.ToString(); 21 } 22 23 //启动线程 24 for (int i = 0; i < 10; i++) 25 { 26 threads[i].Start(); 27 } 28 29 Console.Read(); 30 } 31 }
效果:
lock的语法感觉是很简洁方便的,所以重要的不是怎样用,而是在需要用到线程锁的时后恰当的使用它,这就需要在有多并发、多线程访问的时候考虑一下使用这种锁的机制来避免对程序或者数据造成不可预测的错误。
至于lock(this)与lock(obj)具体的区别,忘高手指点,有的说:不要lock(this),因为在当前类外部的函数可能将这个对象当作lock(obj)的obj。这样可能造成没有想到的死锁,是这样吧?待自己彻底弄清楚后,再来完善本文章..