在上一讲介绍了使用lock来实现线程之间的同步。实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类。先看看下面的C#源代码:

public static void MyLock()

{

    lock (typeof(Program))

    {

    }

}

上面的代码通过lock语句使MyLock同步,这个方法被编译成IL后,代码如图1所示。

图1

从上图被标注的区域可以看到,一条lock语句被编译成了调用Monitor的Enter和Exit方法。Monitor在System.Threading命名空间中。lock的功能就相当于直接调用Monitor的Entry方法,所不同的是,lock方法在结束后,会自动解除锁定,当然,在IL中是调用了Monitor的Exit方法,但在C#程序中,看起来是自动解锁的,这类似于C#中的using语句,可以自动释放数据库等的资源。但如果直接在C#源程序中使用Monitor类,就必须调用Exit方法来显式地解除锁定。如下面的代码所示:

Monitor.Entry(lockObj);

try

{

    // lockObj的同布区

}

catch(Exception e)

{

    // 异常处理代码

}

finally

{

    Monitor.Exit(lockObj);  // 解除锁定

}

Exit方法最后在finally里调用,这样无论在方法在发生异常、返回还是正常执行,都会执行到finally,并调用Exit方法解除锁定。

Monitor类不仅可以完全取代lock语句(如果只使用lock语句本身的功能,最好还是直接用lock语句吧),还可以使用TryEntry方法设置一个锁定超时,单位是毫秒。如下面的代码所示:

if(Monitor.TryEntry(lockObj, ))

{

    try

    {

    }

    finally

    {

        Monitor.Exit(lockObj);

    }

}

else

{

    // 超时后的处理代码

}

上面的代码设置了锁定超时时间为1秒,也就是说,在1秒中后,lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。我们可以使用这种方法来避免死锁,如下面的代码所示:

    class Program

    {

        private static Object objA = new Object();

        private static Object objB = new Object();

        public static void LockA()

        {

            if (Monitor.TryEnter(objA, ))

            {

                Thread.Sleep();

                if (Monitor.TryEnter(objB, ))

                {

                    Monitor.Exit(objB);

                }

                else

                {

                    Console.WriteLine("LockB timeout");

                }

                Monitor.Exit(objA);

            }

            Console.WriteLine("LockA");

        }

        public static void LockB()

        {

            if (Monitor.TryEnter(objB, ))

            {

                Thread.Sleep();

                if (Monitor.TryEnter(objA, ))

                {

                    Monitor.Exit(objA);

                }

                else

                {

                    Console.WriteLine("LockA timeout");

                }

                Monitor.Exit(objB);

            }

            Console.WriteLine("LockB");

        }

        public static void Main()

        {

            Thread threadA = new Thread(LockA);

            Thread threadB = new Thread(LockB);

            threadA.Start();

            threadB.Start();

            Thread.Sleep();         

            Console.WriteLine("线程结束");

        }

    }

上面的代码是在上一讲举的死锁的例子,但在这一讲将lock语句改成了TryEntry方法,而且设置了锁定超时间,由于在等待一定时间后,不管被锁定的对象是否被解锁,TryEntry方法都会返回,因此,上面的代码是不会死锁的。运行上面的代码的结果如图2所示。

图2

如果TryEntry方法的超时时间为System.Threading.Timeout.Infinite,TryEntry方法就相当于Entry方法,如果超时时间为0,不管是否解锁,TryEntry方法都会立即返回。

最新文章

  1. mac下android环境搭建笔记(android studio)
  2. 【MySQL学习笔记】MySQL权限表
  3. csuoj 1329: 一行盒子
  4. nginx的rewrite,gzip,反向代理学习笔记
  5. To add private variable to this Javascript literal object
  6. server2008服务器iis设置的一些经验
  7. QtSpeech会让Qt说话
  8. 17.1.1.6 Creating a Data Snapshot Using Raw Data Files 创建一个数据快照使用 Raw Data Files
  9. 【原创】Libjpeg 库使用心得(一) JPEG图像DCT系数的获取和访问
  10. HDU 5800 To My Girlfriend
  11. Debian 8开启sftp服务
  12. 是什么优化让 .NET Core 性能飙升?
  13. Java读取excel表格
  14. 发送邮件工具类MailHelper
  15. Python Pandas 简单使用之 API熟悉
  16. Windows下安装和卸载MangoDB服务 --MangoDB
  17. 在operator =中要处理“自我赋值”
  18. 闭区间套定理(Nested intervals theorem)讲解1
  19. Appium 点击屏幕
  20. Spring3.x错误----Bean named "txAdvice" must be of type[org.aopallibance.aop.Advice

热门文章

  1. php socket通信(tcp/udp)
  2. php header()函数设置页面Cache缓存
  3. bootstrap 列表 表格 表单 复选 单选 多选 输入框组
  4. mysqldump备份过程中都干了些什么
  5. 20145227 《Java程序设计》第4周学习总结
  6. 【转】MYSQL入门学习之二:使用正则表达式搜索
  7. fastjson和json-lib的区别
  8. 收藏的Android非常好用的组件或者框架。
  9. java实现贪吃蛇游戏
  10. 【linux命令与工具】lsmod命令