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

  • 相关阅读:
    泛函编程(29)-泛函实用结构:Trampoline-不再怕StackOverflow
    泛函编程(28)-粗俗浅解:Functor, Applicative, Monad
    泛函编程(27)-泛函编程模式-Monad Transformer
    泛函编程(26)-泛函数据类型-Monad-Applicative Functor Traversal
    泛函编程(25)-泛函数据类型-Monad-Applicative
    mac安装iterm2
    像使用linux一样使用mac
    springboot工程自动生成工具
    mysql insert返回主键
    linux rz sz命令
  • 原文地址:https://www.cnblogs.com/liu23/p/9136749.html
Copyright © 2020-2023  润新知