這里不考慮分布式或者多臺負(fù)載均衡的情況只考慮單臺機器,多臺服務(wù)器可以使用分布式鎖。出于線程安全的原因,很多種場景大家可能看代碼中看到lock的出現(xiàn),尤其是在資金類的處理環(huán)節(jié)。 但是lock(this)真的達(dá)到你的需求了嗎?下面用實例來說明
成都創(chuàng)新互聯(lián)是專業(yè)的溫江網(wǎng)站建設(shè)公司,溫江接單;提供網(wǎng)站設(shè)計、網(wǎng)站制作,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行溫江網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!
理論常識不多說,回到業(yè)務(wù)場景,舉個例子我們的需求一般就是在某個訂單進(jìn)入某個安全優(yōu)先級比較高的流程時要針對這筆訂單做到線程互斥。至于原因,這里再插一個概念,大部分orm在做更新操作時,實際上做的是全參數(shù)更新,所謂全參數(shù)更新,假如一個訂單表上有10個字段,我們只需要更新其中的一個金額字段,但是在傳統(tǒng)orm框架中實際上在訂單的實體類中賦值了所有字段而在更新操作中這些字段全部參與了更新,所以在高并發(fā)的場景下,如果有2個線程針對同一個訂單操作,并且沒有額外的保護(hù)程序(例如數(shù)據(jù)庫鎖、版本號等)那么在這種傳統(tǒng)框架下后一個線程更新可能就會覆蓋掉前一個線程的操作。因此lock的手段可以看成是一道保護(hù)墻。 那么接下來我們通過實例看一下lock4種不同方式(并非4種類別)之間的區(qū)別
代碼很簡單 在結(jié)果截圖后直接附上
1. Lock(this)
可以看出lock(this),如果this是個普通的類非靜態(tài)非單例,那么lock(this)并不滿足我們的需求,甚至除了當(dāng)前線程并看不出有任何作用。
2. Lock(LockString)
Lock(LockString) 從結(jié)果上來看比較契合要求,對于同一筆訂單做到的線程互斥,對于不同訂單即使用到了同一個類也不干擾。不過根據(jù)大家的回復(fù)意見LockString并不適合鎖。
3. Lock(Object)
Lock(Object)和Lock(this)一樣,因為根本原因2者方式是相同的。推薦!
4. Lock(StaticObject)
Lock(StaticObject) 實現(xiàn)了對于同一筆的訂單線程互斥,但是不符合的是對于不同筆的訂單同樣進(jìn)行了互斥。
結(jié)論一目了然,理論的內(nèi)容不贅述。下面貼代碼
`
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("進(jìn)入鎖并開始操作");
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
}
`
希望對大家有幫助。