Lock关键字的用法

简介: 本文转载:http://www.189works.com/article-8218-1.html 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(私有变量)基本效果都一样,但是都会出现对于多个实例都无法实现互斥。
因此,微软推荐使用私有静态变量作为锁定的变量。但是个人觉得与锁定类和锁定字符串 没有什么不同。
以上只是个人浅见,如有错的地方,请不吝赐教,谢谢。

目录
相关文章
微信小游戏制作工具中,如何跨场景进行交互
微信小游戏制作工具中,如何跨场景进行交互
350 1
|
存储 缓存 芯片
FPGA固件如何进行在线升级?
FPGA固件如何进行在线升级?
1102 0
FPGA固件如何进行在线升级?
SAP MM采购定价过程的一个简单例子
SAP MM采购定价过程的一个简单例子
SAP MM采购定价过程的一个简单例子
|
运维 Docker 容器
如何删除镜像、容器和数据卷?几个值得收藏的docker命令(下)
在docker的实践过程中,如果没有注意docker对磁盘的占用,在某一天你可能发现磁盘空间已经被docker一点点吃掉了。那么今天给大家介绍几个清理docker镜像、容器和数据卷的常用命令。
|
关系型数据库 测试技术 定位技术
PostgreSQL 百亿地理位置数据 近邻查询性能
本文主要要展示的是PostgreSQL在位置信息近邻(KNN)查询方面的性能。 测试类型point,索引类型GiST。 (PostGIS同样支持KNN查询,性能和本文的测试差不多) 测试数据量大于100亿。
20844 1
|
算法 视频直播 Web App开发
直播播流不成功如何排查
本博文将介绍,视频直播加速配置后,播流不成功要如何进行排查及解决;
4709 0
|
SQL Oracle 关系型数据库
|
5天前
|
弹性计算 人工智能 安全
云上十五年——「弹性计算十五周年」系列客户故事(第二期)
阿里云弹性计算十五年深耕,以第九代ECS g9i实例引领算力革新。携手海尔三翼鸟、小鹏汽车、微帧科技等企业,实现性能跃升与成本优化,赋能AI、物联网、智能驾驶等前沿场景,共绘云端增长新图景。
|
11天前
|
存储 弹性计算 人工智能
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
2025年9月24日,阿里云弹性计算团队多位产品、技术专家及服务器团队技术专家共同在【2025云栖大会】现场带来了《通用计算产品发布与行业实践》的专场论坛,本论坛聚焦弹性计算多款通用算力产品发布。同时,ECS云服务器安全能力、资源售卖模式、计算AI助手等用户体验关键环节也宣布升级,让用云更简单、更智能。海尔三翼鸟云服务负责人刘建锋先生作为特邀嘉宾,莅临现场分享了关于阿里云ECS g9i推动AIoT平台的场景落地实践。
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
|
2天前
|
云安全 人工智能 安全
Dify平台集成阿里云AI安全护栏,构建AI Runtime安全防线
阿里云 AI 安全护栏加入Dify平台,打造可信赖的 AI