1、给lock传递参数时首先要避免使用public对象,因为有可能外部程序也在对这个对象加锁
2、避免一下三种锁定
3、使用lock的时候,被lock的对象(locker)一定要是引用类型的,如果是值类型,将导致每次lock的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,C#编译器(3.5.30729.1)在编译时就会给出一个错误)
4、锁定的不仅仅是lock段里的代码,锁本身也是线程安全的
5、初步使用
using System;
using System.Threading.Tasks;
public class Account
{
private readonly object balanceLock = new object();
private decimal balance;
public Account(decimal initialBalance)
{
balance = initialBalance;
}
public decimal Debit(decimal amount)
{
lock (balanceLock)
{
if (balance >= amount)
{
Console.WriteLine($"Balance before debit :{balance, 5}");
Console.WriteLine($"Amount to remove :{amount, 5}");
balance = balance - amount;
Console.WriteLine($"Balance after debit :{balance, 5}");
return amount;
}
else
{
return 0;
}
}
}
public void Credit(decimal amount)
{
lock (balanceLock)
{
Console.WriteLine($"Balance before credit:{balance, 5}");
Console.WriteLine($"Amount to add :{amount, 5}");
balance = balance + amount;
Console.WriteLine($"Balance after credit :{balance, 5}");
}
}
}
class AccountTest
{
static void Main()
{
var account = new Account(1000);
var tasks = new Task[100];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => RandomlyUpdate(account));
}
Task.WaitAll(tasks);
}
static void RandomlyUpdate(Account account)
{
var rnd = new Random();
for (int i = 0; i < 10; i++)
{
var amount = rnd.Next(1, 100);
bool doCredit = rnd.NextDouble() < 0.5;
if (doCredit)
{
account.Credit(amount);
}
else
{
account.Debit(amount);
}
}
}
}