博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NET面试题:C#中的lock关键字有何作用
阅读量:5277 次
发布时间:2019-06-14

本文共 3056 字,大约阅读时间需要 10 分钟。

artType02.jpg NET面试题:C#中的lock关键字有何作用
2011-03-01 08:42:04
标签:

更多.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

你可能感兴趣的文章
Groovy/Spock 测试导论
查看>>
c语言的优先级问题
查看>>
Dynamics 365 CRM Connected Field Service 自动发送command
查看>>
10 行 Java 代码实现 LRU 缓存
查看>>
决策树(Decision Tree)原理
查看>>
HTML5 使用 JS 生成二维码,带头像
查看>>
201771010118马昕璐《面向对象程序设计java》第八周学习总结
查看>>
解决 Windows To Go U盘没有盘符的问题
查看>>
游戏系列~俄罗斯方块(6)
查看>>
贝叶斯理论在机器学习中的应用
查看>>
进击的docker 二 : docker 快速入门
查看>>
Codeforces 362E Petya and Pipes 费用流建图
查看>>
JSBing-js自动绑定C++
查看>>
windows下python虚拟环境virtualenv安装和使用
查看>>
spring--aop总结
查看>>
【原创】android——SQLite的cmd命令的基本操作
查看>>
wordpress插入腾讯视频的方法
查看>>
c++ vector
查看>>
vue中computed(计算属性)和watch在实现父子组件props同步时的实际区分
查看>>
Vue的生命周期
查看>>