• 同步对象 Lock


    对于任何一个对象来说,他在内存中的第一部分放置的是所有方法的地址,第二部分放着一个索引,他指向CLR中的SyncBlock Cache区域中的一个SyncBlock.什么意思呢?就是说,当你执行Monitor.Enter(Object)时,如果object的索引值为负数,就从SyncBlock Cache中选区一个SyncBlock,将其地址放在object的索引中。这样就完成了以object为标志的锁定,其他的线程想再次进行Monitor.Enter(object)操作,将获得object为正数的索引,然后就等待。直到索引变为负数,即线程使用Monitor.Exit(object)将索引变为负数。

    1.不建议lock public性质的类或者属性。例如 lock(this) 或者lock pubilic属性。 容易导致死锁。

    2.建议lock住私有的静态成员变量。

    3.lock住私有非静态变量的,只能保护实例的成员数据,如果临界区是非实例本身的资源或者行为,需要谨慎。

    另外:

    lock(this) 慎用,因为锁定的是整个对象实例,外部也可以锁定该对象,会导致死锁。

    namespace Namespace1
    {
        class C1
         {
            privatebool deadlocked= true;
    
            //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
            publicvoid LockMe(object o)
             {
                lock (this)
                 {
                    while(deadlocked)
                     {
                         deadlocked = (bool)o;
                         Console.WriteLine("Foo: I am locked :(");
                         Thread.Sleep(500);
                     }
                 }
             }
    
            //所有线程都可以同时访问的方法
            publicvoid DoNotLockMe()
             {
                 Console.WriteLine("I am not locked :)");
             }
         }
    
        class Program
         {
            staticvoid Main(string[] args)
             {
                 C1 c1 =new C1();
    
                //在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
                 Thread t1= new Thread(c1.LockMe);
                 t1.Start(true);
                 Thread.Sleep(100);
    
                //在主线程中lock c1
                lock (c1)
                 {
                    //调用没有被lock的方法
                     c1.DoNotLockMe();
                    //调用被lock的方法,并试图将deadlock解除
                     c1.LockMe(false);
                 }
             }
         }
    

    结论是: 在t1线程中,LockMe调用了lock(this), 也就是Main函数中的c1,这时候在主线程中调用lock(c1)时,必须要等待t1中的lock块执行完毕之后才能访问c1,

          即所有c1相关的操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。

     class C1
         {
            privatebool deadlocked= true;
            privateobject locker= newobject();
    
            //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
            publicvoid LockMe(object o)
             {
                lock (locker)
                 {
                    while(deadlocked)
                     {
                         deadlocked = (bool)o;
                         Console.WriteLine("Foo: I am locked :(");
                         Thread.Sleep(500);
                     }
                 }
             }
    
            //所有线程都可以同时访问的方法
            publicvoid DoNotLockMe()
             {
                 Console.WriteLine("I am not locked :)");
             }
         }
    
        class Program
         {
            staticvoid Main(string[] args)
             {
                 C1 c1 =new C1();
    
                //在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
                 Thread t1= new Thread(c1.LockMe);
                 t1.Start(true);
                 Thread.Sleep(100);
    
                //在主线程中lock c1
                lock (c1)
                 {
                    //调用没有被lock的方法 可以执行到 
                     c1.DoNotLockMe();
                    //调用被lock的方法,并试图将deadlock解除
                     c1.LockMe(false);
                 }
             }
         }
    

    这次我们使用一个私有成员作为锁定变量(locker),在LockMe中仅仅锁定这个私有locker,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,DoNotLockMe()仍然可以由主线程访问;LockMe()依然不能访问,原因是其中锁定的locker还没有被t1释放。

    所以,lock(this)的缺点是,容易导致死锁;锁的粒度太大,用lock(this)了,对象内的其他非线程安全的方法不能被访问。

         

        

  • 相关阅读:
    nginx和tomcat访问图片和静态页面的配置方法
    centos7上mysql5.6版本主从复制
    centos7上编译安装mysql5.6
    js去除空格
    屏蔽F1~F12的快捷键的js函数
    js屏蔽浏览器(IE和FireFox)的刷新和右键等功能
    禁止选中页面内容-兼容ie、firefox、chrome
    js获取网页上选中的部分,包含html代码
    一个账号只能在一个地方登陆一次
    c#创建window服务
  • 原文地址:https://www.cnblogs.com/wuMing-dj/p/4901317.html
Copyright © 2020-2023  润新知