博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[C#基础]说说lock到底锁谁?(补充与修改)
阅读量:5965 次
发布时间:2019-06-19

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

摘要

今天在园子里面有园友反馈关于文章中lock(this)的问题。后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修改。

lock(this)

一个例子

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace LockTest{    class Program    {        static void Main(string[] args)        {            TestLock testlock = new TestLock();            Thread th = new Thread(() =>            {                //模拟死锁:造成死锁,使lock无法释放,在i=5时,跳出死循环,释放lock                testlock.DoWorkWithLock();            });            th.Start();            Thread.Sleep(1000);            Thread th2 = new Thread(() =>            {                              //这个地方你可能会有疑惑,但存在这种情况,比如你封装的dll,对其它开发人员不是可见的                //开发人员很有可能在他的逻辑中,加上一个lock保证方法同时被一个线程调用,但这时有其它的线程正在调用该方法,                //但并没有释放,死锁了,那么在这里就不会被执行,除非上面的线程释放了lock锁定的对象。这里的lock也可以理解为一个标识,线程1被锁定的对象                 //是否已经被释放,                 //如果没有释放,则无法继续访问lock块中的代码。                lock (testlock)                {                    // 如果该对象中lock(this)不释放(testlock与this指的是同一个对象),则其它线程如果调用该方法,则会出现直到lock(this)释放后才能继续调用。                      testlock.MotherCallYouDinner();                    testlock.DoWorkWithLock();                }            });            th2.Start();            Console.Read();        }    }    class TestLock    {        public static readonly object objLock = new object();        ///         ///  该方法,希望某人在工作的时候,其它人不要打扰(希望只有一个线程在执行)        ///         ///         public void DoWorkWithLock()        {            //锁当前对象            lock (this)            {                Console.WriteLine("lock this");                int i = 0;                while (true)                {                    Console.WriteLine("At work, do not disturb...,Thread id is " + Thread.CurrentThread.ManagedThreadId.ToString());                    Thread.Sleep(1000);                    if (i == 5)                    {                        break;                    }                    Console.WriteLine(i.ToString());                    i++;                }            }            Console.WriteLine("lock dispose");        }        public void MotherCallYouDinner()        {            Console.WriteLine("Your mother call you to home for dinner.");        }    }}

测试

demo说明:main方法中,创建了一个对象testlock对象,线程1执行该对象的DoWorkWithLock方法,因为死锁(5s后释放),造成lock(this)无法释放,则导致了方法MotherCallYouDinner,DoWorkWithLock在线程2中无法被调用,直到lock(this)释放,lock(testlock)才能继续执行,可以这么理解,由于锁定的同一个对象,线程1释放了锁定的对象,其它线程才能访问。

lock(static readonly object)

那么通过lock(static object)方式呢,能不能保证lock块内的方法,同时只被一个线程执行呢,并且线程2能访问到MotherCallYouDinner方法。而不像上面出现的那种情况,如果不释放lock(this),导致线程2都无法执行代码逻辑。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace LockTest{    class Program    {        static void Main(string[] args)        {            TestLock testlock = new TestLock();            Thread th = new Thread(() =>            {                //模拟死锁:造成死锁,使lock无法释放,在i=5时,跳出死循环,释放lock                testlock.DoWorkWithLock();            });            th.Start();            Thread.Sleep(1000);            Thread th2 = new Thread(() =>            {                                             lock (testlock)                {                                    testlock.MotherCallYouDinner();                    testlock.DoWorkWithLock();                }            });            th2.Start();            Console.Read();        }    }    class TestLock    {        public static readonly object objLock = new object();        ///         ///  该方法,希望某人在工作的时候,其它人不要打扰(希望只有一个线程在执行)        ///         ///         public void DoWorkWithLock()        {            //锁            lock (objLock)            {                Console.WriteLine("lock this");                int i = 0;                while (true)                {                    Console.WriteLine("At work, do not disturb...,Thread id is " + Thread.CurrentThread.ManagedThreadId.ToString());                    Thread.Sleep(1000);                    if (i == 5)                    {                        break;                    }                    Console.WriteLine(i.ToString());                    i++;                }            }            Console.WriteLine("lock dispose");        }        public void MotherCallYouDinner()        {            Console.WriteLine("Your mother call you to home for dinner.");        }    }}

测试

可以看到,将lock(this)更换为锁定私有的静态对象,线程2执行了,首先输出了“Your mother call you to home for dinner.”,同时实现了DoWorkWithLock方法中lock的代码块当前只被一个线程执行,直到lcok(objlock)被释放。因为锁定的对象,外部不能访问,线程2不再关心lock(this)是不是已经释放,都会执行,当然也保证了方法DoWorkWithLock同时被一个线程访问。

总结

1、避免使用lock(this),因为无法保证你提供的方法,在外部类中使用的时候,开发人员会不会锁定当前对象。

通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:

  • 如果实例可以被公共访问,将出现 lock (this) 问题。

  • 如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。

  • 由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。

最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。

这里只是说明lock(this)的问题,虽然极端。但开发中,不能保证不会发生。

2、最好使用私有的静态只读的锁对象,保证不会影响其他逻辑的正常执行。

3、尽量避免死锁的发生。

资料,如果仍然不明白可以参考下面的链接

非常感谢,@咕-咚 在上篇文章中,对demo提出的疑问,引发进一步的思考。当然,如果还有不妥的地方,欢迎指正,讨论。

转载于:https://www.cnblogs.com/wolf-sun/p/8405541.html

你可能感兴趣的文章
Linux备份ifcfg-eth0文件导致的网络故障问题
查看>>
2018年尾总结——稳中成长
查看>>
JFreeChart开发_用JFreeChart增强JSP报表的用户体验
查看>>
度量时间差
查看>>
通过jsp请求Servlet来操作HBASE
查看>>
Shell编程基础
查看>>
Shell之Sed常用用法
查看>>
3.1
查看>>
校验表单如何摆脱 if else ?
查看>>
<气场>读书笔记
查看>>
Centos下基于Hadoop安装Spark(分布式)
查看>>
3D地图的定时高亮和点击事件(基于echarts)
查看>>
mysql开启binlog
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
Mysql 监视工具
查看>>
从前后端分离到GraphQL,携程如何用Node实现?\n
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>
博客搬家了
查看>>