多线程中lock的使用
lock的定义:
lock关键字可以用来确保代码块的完成运行,而不会被其他线程中断,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。这是通过在代码块运行期间为给定对象获取互斥锁来实现的。
lock关键字定义:
如果你想定义一个类的实例,一般地,你可以使用this;如果你想保护一个静态变量(如互斥代码段在一个静态方法内部),一般使用类名就可以了。
简单介绍一下lock的执行过程
先来看看执行过程,代码示例如下:
private static object ojb = new object();
lock(obj)
{
//锁定运行的代码段
} 假设线程A先执行,线程B稍微慢一点。线程A执行到lock语句,判断obj是否已申请了互斥锁,判断依据是逐个与已存在的锁进行object.ReferenceEquals比较(此处未加证实),如果不存在,则申请一个新的互斥锁,这时线程A进入lock里面了。
这时假设线程B启动了,而线程A还未执行完lock里面的代码。线程B执行到lock语句,检查到obj已经申请了互斥锁,于是等待;直到线程A执行完毕,释放互斥锁,线程B才能申请新的互斥锁并执行lock里面的代码。
以上是网上的说话,下面谈谈我的理解:
一般来说多线程中,使用有静态变量这种,或者你想保证数据完全执行到的就需要加锁了
需要注意的是:
一:多线程加锁范围太大,虽然会避免逻辑上的问题,难免会降低程序的效率。
二:该锁的不锁会导致莫名奇妙的错误
三:加锁方式不合适,也会降低程序的效率
实例:
下面的例子,仅供参考,只是自己随手一写,也没有测试代码的正确度,主要是对线程锁lock的了解
有这样一个例子,我在新增一个方法的时候,同时想在表格新增其他字展示在表格里面
首先是查询所有人的信息
/// <summary> /// 获取学生的集合 /// </summary> /// <returns></returns> public static List<Student> GetStudent() { List<Student> list = new List<Student>(); list.Add(new Student() { Sid = 1, Sname = "张三", Sex = "男", Age = 12 }); list.Add(new Student() { Sid = 2, Sname = "李四", Sex = "女", Age = 13 }); list.Add(new Student() { Sid = 3, Sname = "王五", Sex = "男", Age = 14 }); list.Add(new Student() { Sid = 4, Sname = "赵六", Sex = "男", Age = 15 }); return list; }
获取一下person的消息
_spDic为了记录除了表格本身之外的数据,这里当然会出错,我只是做一个赋值,用_spDic记录数据而已
static Dictionary<Person, Student> _spDic = new Dictionary<Person, Student>(); // public static List<Person> GetPeopleItem() { List<Student> list1 = GetStudent(); List<Person> list2 = new List<Person>(); Person person = new Person(); foreach (Student item in list1) { person.Pid = item.Sid; person.Pname = item.Sname; person.Sex = item.Sex; person.Age = item.Age; list2.Add(person); if (person.Pid > 0) { lock (_spDic) { _spDic.Add(person, item); } } } return list2; }
调用static void Main(string[] args)
{ List<Person> list = GetPeopleItem(); foreach (var item in list) { Console.WriteLine(item.Pid); Task.Factory.StartNew(() => { //这里面实现了功能的新增
..............
lock (_spDic) { _spDic.Remove(item); } }); } Console.ReadKey(); }
这时候我在实现新增后,就移除了他的数据也是需要加锁的,这样才能保证数据完全可以执行到.
注意:
应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则: 1)如果实例可以被公共访问,将出现 lock (this) 问题; 2)如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题; 3)由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock("myLock") 问题; 最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。