zoukankan      html  css  js  c++  java
  • 异步多线程(六)lock锁

    非线程安全

       引发线程安全的原因是,多个线程可以同时操作全局变量/共享变量/静态变量/磁盘文件/数据库的值就可能存在线程安全问题,因为多个线程操作,出现了覆盖。List集合也是非线程安全的。

    线程安全

    多线程同时运行,如果每次运行的结果和单线程运行的结果一致,那么就是线程安全的。

    Lock

    概念

       解决多线程冲突问题,Lock是语法糖,Monitor.Enter,占据一个引用,别的线程就只能等着。锁的本质就是把多线程在某些特定场合下变成单线程,来完成某些特定操作。

    在日常工作中,有些是特定需要锁的,更多的时候我们可以把数据拆分,避免多线程操作同一个数据,这样既安全又高效。例如有10000个任务,那可以进行拆分,某个线程执行1-100给任务。

    Lock锁不允许的类型

      Stringstring在内存分配上是重用的,会冲突。这么话应该这么理解,比如你定义一个变量name=张三”,再定义一个变量temeName=张三,那么在C#内存分配时会指向同一个引用。

      Null:可以运行,不能编译通过。

    详解Lock

    Lock锁的两钟方式:

    Lock(this)不推荐的锁如果只是当前内部实例使用,则不会冲突。外面如果也要用实例,就冲突了。 

            public void DoTest() {
                //递归调用 lock(this)不会死锁,原因:这里是同一个线程,这个引用就是被这个线程锁占据
                //锁的本质是让这个引用不会被其他线程所占据
            lock (this)
            {
                    Thread.Sleep(500);
                    iDotestNum++;
                    if (DateTime.Now.Day < 13&&iDotestNum<10)
                    {
                        
                        Console.WriteLine($"这是第{DateTime.Now.Day}天,第{iDotestNum}次");
                        this.DoTest();
                    }
                    else {
                        Console.WriteLine("结束啦");
                    }
                    }
            }
    
            private int iDotestNum = 0;

    外部也要使用实例:

                Test test = new Test();
                Task.Delay(1000).ContinueWith(t =>
                {
                    lock (test)//此处是锁住test实例
                    {
                        Console.WriteLine("*********Start**********");
                        Thread.Sleep(5000);
                        Console.WriteLine("*********End**********");
                    }
                });
                //会冲突,因为DoTest方法里的lock(this)就是锁住当前的实例即:test
                test.DoTest();
    
            public class Test{ 
    
            public void DoTest() {
                //递归调用 lock(this)不会死锁,原因:这里是同一个线程,这个引用就是被这个线程锁占据
                //锁的本质是让这个引用不会被其他线程所占据
            lock (this)
            {
                    Thread.Sleep(500);
                    iDotestNum++;
                    if (DateTime.Now.Day < 13&&iDotestNum<10)
                    {
                        
                        Console.WriteLine($"这是第{DateTime.Now.Day}天,第{iDotestNum}次");
                        this.DoTest();
                    }
                    else {
                        Console.WriteLine("结束啦");
                    }
                    }
            }
    
            private int iDotestNum = 0;
        }

    标准锁,微软推荐的标准锁

    private static readonly object Form_Lock = new object();

    lock(Form_Lock);

                #region 标准锁
    
                for (int i = 0; i < 1000; i++)
                {      
                       Task.Run(() =>
                       {
                           lock (Form_Lock)// 任意时刻只有一个线程能进入方法块儿
                           {
                               intAsyncNum++;
                           }
                       });
                }
                Console.WriteLine($"intAsyncNum={intAsyncNum}");
    
                #endregion
  • 相关阅读:
    PHP全部手册
    你必须收藏的GitHub技巧
    PV和并发
    api接口
    LeetCode 14. 最长公共前缀
    LeetCode 1037. 有效的回旋镖
    LeetCode 242. 有效的字母异位词
    LeetCode 151. 翻转字符串里的单词
    LeetCode 22. 括号生成
    LeetCode 面试题05. 替换空格
  • 原文地址:https://www.cnblogs.com/JohnTang/p/11010476.html
Copyright © 2011-2022 走看看