NET面试题:C#中的lock关键字有何作用

2011-03-01 08:42:04

标签:.net面试题 .net电子书 .net教学视频 .net

更多.net面试题,.net电子书,.net教学视频请参考"51CTO提醒您,请勿滥发广告!"

NET面试题:C#中的lock关键字有何作用
作为C#的程序员来说,在遇到线程同步的需求时最常用的就是lock关键字。但如何正确并有效地使用lock却是能否高效地达到同步要求的关键。正因为如此,程序员需要完全理解lock究竟为程序做了什么。
  所涉及的知识点
· lock的等效代码
· System.Threading.Monitor类型的作用和使用方法
  分析问题
1.lock的等效代码
在.NET的多线程程序中,经常会遇到lock关键字来控制同步,比如下列代码:
private object o = new object();
public void Work()
{
lock(o)
{
  //做一些需要线程同步的工作
}
}
事实上,lock这个关键字是C#为方便程序员而定义的语法,它等效于安全地使用System.Threading.Monitor类型。上面的代码就直接等效于下面的代码:
private object o = new object();
public void Work()
{
//这里很重要,是为了避免直接使用私有成员o,而导致线程不安全
Object temp = o;
System.Threading.Monitor.Enter(temp);
try
{
  //做一些需要线程同步的工作
}
finally
{
  System.Threading.Monitor.Exit(temp);
}
}
正如读者所看到的,真正实现了线程同步功能的,就是System.Threading.Monitor类型,lock关键字只是用来代替调用Enter、Exit方法,并且将所有的工作包含在try块内以保证其最终退出同步。
2.System.Threading.Monitor类型的作用和使用
在前文中笔者已经提到了,Monitor类型的Enter和Exit方法用来实现进入和退出对象的同步。具体来说,当Enter方法被调用时,对象的同步索引将被检查,并且.NET将负责一系列的后续工作来保证对象访问时线程的同步,而Exit方法的调用,则保证了当前线程释放该对象的同步块。
代码7-13演示了如何利用lock关键字(也就是Monitor类型)来实现线程同步,具体定义了一个包含需要同步执行方法的类型。
代码7-13  线程同步:UseLock.cs
    /// <summary>
    /// 演示同步锁
    /// </summary>
    public class Lock
    {
        //用来在静态方法中同步
        private static Object o1 = new object();
        //用来在成员方法中不同
        private Object o2 = new object();
        //成员变量
        private static int i1 = 0;
        private int i2 = 0;
        /// <summary>
        /// 测试静态方法的同步
        /// </summary>
        /// <param name="state">状态对象</param>
        public static void Increment1(Object state)
        {
            lock (o1)
            {
                Console.WriteLine("i1的值为:{0}", i1.ToString());
                //这里刻意制造线程并行机会
                //来检查同步的功能
                Thread.Sleep(200);
                i1++;
                Console.WriteLine("i1自增后为:{0}", i1.ToString());
            }
        }
        /// <summary>
        /// 测试成员方法的同步
        /// </summary>
        /// <param name="state">状态对象</param>
        public void Increment2(Object state)
        {
            lock (o2)
            {
                Console.WriteLine("i2的值为:{0}", i2.ToString());
                //这里刻意制造线程并行机会
                //来检查同步的功能
                Thread.Sleep(200);
                i2++;
                Console.WriteLine("i2自增后为:{0}", i2.ToString());
            }
        }      
    }
这样,在main方法中调用该类型对象的方法和其静态方法,测试其同步的效果,如代码7-14所示。
代码7-14  线程同步:UseLock.cs
/// <summary>
/// 程序入口
/// </summary>
class MainClass
{
    /// <summary>
    /// 测试同步效果
    /// </summary>
    static void Main(string[] args)
    {
        //开始多线程
        Console.WriteLine("开始测试静态方法的同步");
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(Lock.Increment1);
            t.Start();
        }
        //这里等待线程执行结束
        Thread.Sleep(5*1000);
        Console.WriteLine("开始测试成员方法的同步");
        Lock l = new Lock();
        //开始多线程
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(l.Increment2);
            t.Start();
        }
        Console.Read();
    }
}
下面是程序的执行结果:
开始测试静态方法的同步
i1的值为:0
i1自增后为:1
i1的值为:1
i1自增后为:2
i1的值为:2
i1自增后为:3
i1的值为:3
i1自增后为:4
i1的值为:4
i1自增后为:5
开始测试成员方法的同步
i2的值为:0
i2自增后为:1
i2的值为:1
i2自增后为:2
i2的值为:2
i2自增后为:3
i2的值为:3
i2自增后为:4
i2的值为:4
i2自增后为:5
可以看到,线程同步被很好地保证了。这里需要强调的是,线程同步本身违反了多线程并行运行的原则,所以读者在使用线程同步时应该尽量做到把lock加在最小的程序块上。如果一个方法有大量的代码需要线程同步,那就需要重新考虑程序的设计了,是否真的有必要进行多线程处理,毕竟线程本身的开销也是相当大的。
对静态方法的同步,一般采用静态私有的引用成员,而对成员方法的同步,一般采用私有的引用成员。读者需要注意静态和非静态成员的使用和把同步对象申明为私有,这都是保证线程同步高效并且正确的关键点。
  答案
C#中的lock关键字实质是调用Monitor.Enter和Monitor.Exit两个方法的简化语法,功能上其实现了进入和退出某个对象的同步。在通常情况下,可以通过lock一个私有的引用成员变量来完成成员方法内的线程同步,而通过lock一个私有的静态引用成员变量来完成静态方法内的线程同步

转载于:https://www.cnblogs.com/mingyongcheng/archive/2011/03/27/1996716.html

NET面试题:C#中的lock关键字有何作用相关推荐

  1. 一起谈.NET技术,C#中的lock关键字

    前几天与同事激烈讨论了一下,有一点收获,记录起来. 首先给出MSDN的定义: lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.这是通过在代码块运行期间为给定对象获取互斥锁来实现的. ...

  2. Haskell / GHC中的“ forall”关键字有什么作用?

    本文翻译自:What does the `forall` keyword in Haskell/GHC do? I'm beginning to understand how the forall k ...

  3. java中的native关键字有什么作用?(java本地方法)

    转自: http://zhidao.baidu.com/link?url=Xu94DBMxXz3sJyCrG7G1sCmXoHuyuYx4DMG1x7UqYL7FhfFnqF7-Z9nxIQUpntP ...

  4. 转:C#中Monitor对象与Lock关键字的区别分析

    Monitor对象1.Monitor.Enter(object)方法是获取 锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取 ...

  5. C#中Lock关键字的使用

    C# 中的 Lock 语句通过隐式使用 Monitor 来提供同步功能.lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit. 通常,应避免锁定 public 类型,否则实例将超 ...

  6. 简单聊聊C#中lock关键字

    为了避免多个线程同时操作同一资源,引起数据错误,通常我们会将这个资源加上锁,这样在同一时间只能有一个线程操作资源.在C#中我们使用lock关键字来锁定资源,那lock关键字是如何实现锁定的呢? 我们先 ...

  7. 描述C#多线程中 lock关键字

    本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待. 每个线程都 ...

  8. java volatile lock_Java并发学习笔记 -- Java中的Lock、volatile、同步关键字

    Java并发 一.锁 1. 偏向锁 1. 思想背景 来源:HotSpot的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同 一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁 ...

  9. C#中lock关键字的用法

    C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待. 每个线程都有自己的资源,但是代码区是共享 ...

最新文章

  1. Entity Framework Core 批处理语句
  2. 11-散列3 QQ帐户的申请与登陆 (25 分)
  3. mysql安装(glibc版本安装5.7.22)
  4. mssql如何取得两位的月份和天数
  5. mysql中数据定义和数据控制语言_MySQL的DDL数据定义语言和DCL数据控制语言
  6. 5G 之战让运营商备受冷落?! | 极客头条
  7. 常用模拟键键值对照表(Virtual-Key Codes)
  8. 【渝粤题库】 陕西师范大学 202331 证券投资学 作业(专升本)
  9. linux下wav转换为mp3
  10. 【正一专栏】阿根廷和葡萄牙都进不了世界杯可能吗?
  11. 世界四大名柚有哪些?
  12. 心理学效应:阿基米德与酝酿效应
  13. 教你快速开发一个 狼人杀微信小程序(附源码)
  14. 学计算机的人会单身吗,大学里最易单身的十大专业
  15. 《王者荣耀游戏服务器架构演进(完整版)》读后感
  16. Linux下移动硬盘,创建windows,ntfs分区并挂载
  17. 真·骚操作!程序员埋逻辑炸弹,每隔几年就触发
  18. 第13周项目4 立体类族公有的抽象类
  19. 【k8s】Error response from daemon: Get https://192.168.22.234/v2/: dial tcp 192.168.22.234:443: connec
  20. MATLAB图像识别手写数字(第一篇:准备数据)

热门文章

  1. c# 找出目录下的所有子目录_第9期:Linux下文件系统满的处理
  2. html中下拉列表监听事件,ExtJS 下拉框监听事件、日期选择器监听事件、实现动态给items添加删除数据...
  3. learning to rank
  4. word中公式编辑器编号
  5. 2022.3.25黄花酢浆草
  6. NOIP2016普及组第四题——魔法阵
  7. android studio标题怎么改,如何在Android Studio中将应用标题更改为徽标
  8. 如何查看cplex的help文档_用摹客,写出更好的产品文档
  9. Linux系统下安装卸载jdk
  10. 机器学习---实战---K-近邻算法--笔记