0
点赞
收藏
分享

微信扫一扫

深入理解.Net中的锁(一)为什么不建议使用Lock

GG_lyf 2022-04-13 阅读 30

在CLR Via C#一书中作者说了,他不推荐在任何时候使用lock,说实话,我们在很多时候还是会为了方便,在一些简单的场景中,还是会顺手就使用lock,那么为什么不建议使用lock呢?今天就来详细说说。
先上代码
代码环境为.Net4.6.1,因为.net6中Thread.CurrentThread.Abort()方法被弃用了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{

    public class TestServer
    {
        LockTest1 lockTest = new LockTest1();
        public void TestStart()
        {
            LockTest1 lockTest = new LockTest1();
            for (int i = 0; i < 10; i++)
            {

                Thread t = new Thread(() => {
                    //lockTest.MethodLock();
                    lockTest.MethodMonitor();
                    //  lockTest.MethodMonitorUp();
                });
                t.Start();

            }
        }
    }

    /// <summary>
    /// 锁测试代码 基于.Net4.6.1
    /// </summary>
    public class LockTest1
    {

        private readonly static Object objLock = new Object();
        private int j = 0;

        /// <summary>
        /// Lock方法
        /// </summary>
        public void MethodLock()
        {
            try
            {
                lock (objLock)
                {
                    var x = Thread.CurrentThread.ManagedThreadId;
                    for (int i = 0; i < 10; i++)
                    {
                  
                        Thread.Sleep(10);
                        j += 1;
                        Console.WriteLine($"================{j}  线程ID:{x.ToString("00")} ");
                    }
                    Console.WriteLine($"=====执行完成======{j}  线程ID:{x.ToString("00")} ");
                }
            }
            finally
            {

            }
        }
        /// <summary>
        /// Lock底层实现方法
        /// </summary>
        public void MethodMonitor()
        {
            try
            {
                var x = Thread.CurrentThread.ManagedThreadId;
                //x 需要根据自己的线程进行修改
                if (x == 10)
                {
                    Thread.CurrentThread.Abort();
                }
  
                Monitor.Enter(this);
                for (int i = 0; i < 10; i++)
                {

                    Thread.Sleep(10);
                    j += 1;
                    Console.WriteLine($"================{j}  线程ID:{x.ToString("00")} ");
                }
                Console.WriteLine($"=====执行完成======{j}  线程ID:{x.ToString("00")} ");
            }
            finally
            {
                try
                {
                    //永远会退出
                    Monitor.Exit(this);
                }
                catch (Exception ex)
                {

   
                }
   
            }
        }

        /// <summary>
        /// 优化后的Lock底层实现方法
        /// </summary>
        public void MethodMonitorUp()
        {
            Boolean lockTaken = false;
            try
            {
                var x = Thread.CurrentThread.ManagedThreadId;
                //x 需要根据自己的线程进行修改
                if (x == 10)
                {
                    Thread.CurrentThread.Abort();
                }
                Monitor.Enter(this, ref lockTaken);
                for (int i = 0; i < 10; i++)
                {

                    Thread.Sleep(10);
                    j += 1;
                    Console.WriteLine($"================{j}  线程ID:{x.ToString("00")} ");
                }
                Console.WriteLine($"=====执行完成======{j}  线程ID:{x.ToString("00")} ");
            }
            finally
            {
                if (lockTaken)
                {
                    Monitor.Exit(this);
                }
            }
        }

    }
}

  • MethodMonitor可以看着lock的底层实现,注意看异常处理部分,无论如何,总是会释放锁,这样保证了锁的获取。但是,当线程突然被终止时,此时线程并没有获取锁,但是仍然要求释放锁,当然就会出现System.Threading.SynchronizationLockException:“从不同步的代码块中调用了对象同步方法。”异常。对于多线程来说,这样会使锁的状态被损坏,下一个线程会获取到一个损坏状态的锁,进而造成不安全的代码。而且try catch 也会在不同的编译器下影线程序性能。
  • MethodMonitorUp代码中,添加lockTaken变量后,这个问题就可以被解决了,如果没有获取到锁,则不会要求释放锁。
  • 由此我们也可以知道lock其实是一个moitor的语法糖.
举报

相关推荐

0 条评论