• Lock关键字的用法


    本文转载:http://www.189works.com/article-8218-1.html

     Lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

     Lock关键字用途主要是解决多线程下限制同时访问同一个对象。

    摘要: 一直以来对于lock关键字的用法都存有疑惑,也从网上看到很多关于他的资料包括MSDN,无奈MSDN讲述的真是让人上火。今天决定小小研究一下一直都知道lock是锁定某一变量从而实现对某一代码段的独占执行。但是对于lock(t ...

    一直以来对于lock关键字的用法都存有疑惑,也从网上看到很多关于他的资料包括MSDN,无奈MSDN讲述的真是让人上火。今天决定小小研究一下
    一直都知道lock是锁定某一变量从而实现对某一代码段的独占执行。
    但是对于lock(this)、lock(typeof(类名))、lock(字符串)、lock(公有变量) lock(私有变量) 有什么不同 却很是模糊
    我假定了这样一种场景:某个时刻,只允许一个客户在打电话
    定义一个客户类
    代码1:(lock(this))
    ///定义一个Custmer类,要求某一时间,只允许一个客户在打电话 
    public class Custmer
        {
            public Custmer()
            {
            }
            public Custmer(string name)
            {
                _name = name;
            }
        ///某一时刻只允许一个客户在打电话
            public void getPhone()
            {
                lock (this)
                {
                        for (int i = 0; i < 10; i++)
                        {
                            Console.WriteLine(Thread.CurrentThread.Name+"正在跟客户在通话");
                            Thread.Sleep(1000);
                        }
                }
            }
        }
    在主函数中调用,先实例化一个Custmer 实例
      static void Main(string[] args)
            {
                Custmer c=new Custmer();
                Thread t1 = new Thread(new ThreadStart(c.getPhone));
                t1.Name = "t1";
                Thread t2 = new Thread(new ThreadStart(c.getPhone));
                t2.Name = "t2";
                t1.Start();
                t2.Start();
                Console.Read();
            }
    可以预先分析一下结果,因为用的是lock(this),而this这时候代表的是实例c,当其中一个线程在使用的时候,另一个线程是不能使用的。也就是说,结果应该是其中一个线程先使用,另一个再使用,而不是交替使用。
    运行结果1:


    跟预想的结果一样,但是如果是多个客户实例呢,结果有怎样
    代码2:
    代码
      static void Main(string[] args)
            {
                //这里我实例化了两个客户类
                Custmer c=new Custmer();
                Custmer c2 = new Custmer();
               //线程1去接通c的电话
                Thread t1 = new Thread(new ThreadStart(c.getPhone));
                t1.Name = "t1";
               //线程2去接通c2的电话
                Thread t2 = new Thread(new ThreadStart(c2.getPhone));
                t2.Name = "t2";
                t1.Start();
                t2.Start();
                Console.Read();
            }
    再预想一下结果,对于线程t1,跟客户c接通电话,此时lock(this)中的this是当前实例c。同理,对于线程t2,this是实例c2.这样lock(this)锁定的是不同的对象,所以无法达到某一时刻,只有一个客户在电话。也就是说,两个线程会交替执行。
    执行结果2:


    与预想结果一样。从这里我们知道,lock(this)存在多个实例间互斥不能实现的问题,原因在于this指向的是不同的实例
    另外在有的地方说lock(this)可能会造成死锁,所谓的死锁,无非就是一个线程长期锁定this不释放。 可能是lock锁定的代码段是个死循环,也可能你在一个死循环里调用lock锁定的代码段。总之是没有释放锁定对象。
    Lock(typeof(类名))
    我重新定义了一个sales类,用来在Customer类中锁定它
    sales类
    public class sales
        {
            public sales(string name)
            {
                _name = name;
            }
            string _name;
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }
        }
    Customer类改写如下:
    public class Custmer
        {
            public Custmer()
            {
            }
            public Custmer(string name)
            {
                _name = name;
            }      
            string _name;
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }
            public void getPhone()
            {
                lock (typeof(sales))//关键是这里
                {
                        for (int i = 0; i < 10; i++)
                        {
                            Console.WriteLine(Thread.CurrentThread.Name+"正在跟客户在通话");
                            Thread.Sleep(1000);
                        }
                }
            }
        }
    我们在主函数中,调用如Lock(this)的单个实例的情况,我们会发现,实现了互斥。多个实例的情况也实现了互斥。但是又有了新的问题。因为我们锁定的是类本身,所以如果有一个地方是在使用类,那么其他地方就不能使用该类,这样的限制过于苛刻。
    3.Lock(字符串)
    这个就更好玩了,他是实现了绝对的互斥。只要字符串内容相同,就能引起程序挂起。原因是在.NET中,字符串会被暂时存放,如果两个变量的字符串内容相同的话,.NET会把暂存的字符串对象分配给该变量。所以如果有两个地方都在使用lock(字符串)的话,它们实际锁住的是同一个对象。
    那我们看一下代码和执行结果
    代码:
        public class Custmer
        {
            string flag = "ATually";//定义了一个字符串变量
            public Custmer()
            {
            }
            public Custmer(string name)
            {
                _name = name;
            }
            string _name;
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }
            public void getPhone()
            {
                lock (flag)//关键是这里
                {
                        for (int i = 0; i < 10; i++)
                        {
                            Console.WriteLine(Thread.CurrentThread.Name+"正在跟客户在通话");
                            Thread.Sleep(1000);
                        }
                }
            }
        }
    多个实例的情况下的执行结果也实现了互斥。
    对于Lock(共有变量)和Lock(私有变量)基本效果都一样,但是都会出现对于多个实例都无法实现互斥。
    因此,微软推荐使用私有静态变量作为锁定的变量。但是个人觉得与锁定类和锁定字符串 没有什么不同。
    以上只是个人浅见,如有错的地方,请不吝赐教,谢谢。

  • 相关阅读:
    一个分页的存储过程
    自己动手:修改crx文件制作自己的Chrome Apps
    SQLSERVER 过滤所有权的代码
    在ASP.NET中实现多文件上传
    引用 TimeSpan简介
    xml
    常用的正则表达式小结
    ASP.NET事务处理
    创建可在网页下载安装的ActiveX控件(通过Setup.exe安装)
    ASP.NET验证控件应用实例与详解
  • 原文地址:https://www.cnblogs.com/51net/p/2955862.html
Copyright © 2020-2023  润新知