多线程中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 对象变量来保护所有实例所共有的数据。

 

posted @ 2018-06-05 00:34  Chin_lung  阅读(536)  评论(0编辑  收藏  举报