這里不考慮分布式或者多台負載均衡的情況只考慮單台機器,多台服務器可以使用分布式鎖。出於線程安全的原因,很多種場景大家可能看代碼中看到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)
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 }
希望對大家有幫助。