【C#|.NET】lock(this)實際上是個坑

  這裏不考慮分佈式或者多臺負載均衡的狀況只考慮單臺機器,多臺服務器能夠使用分佈式鎖。出於線程安全的緣由,不少種場景你們可能看代碼中看到lock的出現,尤爲是在資金類的處理環節。 可是lock(this)真的達到你的需求了嗎?下面用實例來講明數據庫

  理論常識很少說,回到業務場景,舉個例子咱們的需求通常就是在某個訂單進入某個安全優先級比較高的流程時要針對這筆訂單作到線程互斥。至於緣由,這裏再插一個概念,大部分orm在作更新操做時,實際上作的是全參數更新,所謂全參數更新,假如一個訂單表上有10個字段,咱們只須要更新其中的一個金額字段,可是在傳統orm框架中實際上在訂單的實體類中賦值了全部字段而在更新操做中這些字段所有參與了更新,因此在高併發的場景下,若是有2個線程針對同一個訂單操做,而且沒有額外的保護程序(例如數據庫鎖、版本號等)那麼在這種傳統框架下後一個線程更新可能就會覆蓋掉前一個線程的操做。所以lock的手段能夠當作是一道保護牆。 那麼接下來咱們經過實例看一下lock4種不一樣方式(並不是4種類別)之間的區別安全

  代碼很簡單 在結果截圖後直接附上服務器

   1. Lock(this)併發

  

  能夠看出lock(this),若是this是個普通的類非靜態非單例,那麼lock(this)並不知足咱們的需求,甚至除了當前線程並看不出有任何做用。負載均衡

  2. Lock(LockString)框架

  

   Lock(LockString) 從結果上來看比較契合要求,對於同一筆訂單作到的線程互斥,對於不一樣訂單即便用到了同一個類也不干擾。不過根據你們的回覆意見LockString並不適合鎖。分佈式

  3. Lock(Object)高併發

  

  Lock(Object)和Lock(this)同樣,由於根本緣由2者方式是相同的。推薦!測試

  4. Lock(StaticObject)this

  

  Lock(StaticObject) 實現了對於同一筆的訂單線程互斥,可是不符合的是對於不一樣筆的訂單一樣進行了互斥。

  結論一目瞭然,理論的內容不贅述。下面貼代碼

  

class Program
    {
        const string firstOrderId = "001";
        const string secondOrderId = "002";
        const string thirdOrderId = "003";

        static void Main()
        {
            test(LockType.LockThis);
            //test(LockType.LockString);
            //test(LockType.LockObject);
            //test(LockType.LockStaticObject);

            Console.ReadLine();
        }

        static void test(LockType lockType)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("------------測試相同訂單------------");
            Console.ForegroundColor = ConsoleColor.White;
            OrderPay(firstOrderId, 1, lockType);
            OrderPay(firstOrderId, 2, lockType);
            OrderPay(firstOrderId, 3, lockType);
            Thread.Sleep(10000);

            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("------------測試不一樣訂單------------");
            Console.ForegroundColor = ConsoleColor.White;
            OrderPay(firstOrderId, 1, lockType);
            OrderPay(secondOrderId, 1, lockType);
            OrderPay(thirdOrderId, 1, lockType);
        }

        static void OrderPay(string orderId, int threadNo, LockType lockType)
        {
            new Thread(() => new Payment(orderId, threadNo).Pay(lockType)).Start();

            Thread.Sleep(10);
        }
    }

  

    public class Payment
    {
        private readonly string LockString;
        public readonly int ThreadNo;
        private readonly Object LockObj = new object();
        private static readonly Object StaticLockObj = new object();

        public Payment(string orderID, int threadNo)
        {
            LockString = orderID;
            ThreadNo = threadNo;
        }

        public void Pay(LockType lockType)
        {
            ShowMessage("等待鎖資源");
            switch (lockType)
            {
                case LockType.LockThis:
                    lock (this)
                    {
                        showAction();
                    }
                    break;
                case LockType.LockString:
                    lock (LockString)
                    {
                        showAction();
                    }
                    break;
                case LockType.LockObject:
                    lock (LockObj)
                    {
                        showAction();
                    }
                    break;
                case LockType.LockStaticObject:
                    lock (StaticLockObj)
                    {
                        showAction();
                    }
                    break;
            }
            ShowMessage("釋放鎖");
        }

        private void showAction()
        {
            ShowMessage("進入鎖並開始操做");
            Thread.Sleep(2000);
            ShowMessage("操做完成,完成時間爲" + DateTime.Now);
        }

        private void ShowMessage(string message)
        {
            Console.WriteLine(String.Format("訂單{0}的第{1}個線程 {2}", LockString, ThreadNo, message));
        }

    }

    public enum LockType
    {
        LockThis = 0,
        LockString = 1,
        LockObject = 2,
        LockStaticObject = 3
    }

  但願對你們有幫助。

相關文章
相關標籤/搜索