Để giảm thiểu tác dụng phụ, đối tượng bị khóa không nên là đối tượng bị thao tác mà là một đối tượng riêng biệt được chỉ định khóa.
Tùy thuộc vào yêu cầu của bạn, có một vài lựa chọn để xử lý vấn đề này:
Variant A: Private đối tượng khóa
Chọn nút này nếu bạn chỉ muốn đảm bảo rằng DoSomething
không xung đột với một thể hiện song song của DoSomething
.
private static readonly object doSomethingLock = new object();
public static void DoSomething (string param1, string param2, SomeObject o)
{
//.....
lock(doSomethingLock)
{
o.Things.Add(param1);
o.Update();
// etc....
}
}
Biến thể B: Vượt qua khóa đối tượng như một tham số
Chọn này nếu truy cập vào o
phải được thread-an toàn ngay cả bên ngoài DoSomething
, ví dụ, nếu khả năng tồn tại mà người khác viết một phương pháp DoSomethingElse
mà chạy song song với DoSomething
và đó không phải can thiệp với khối lock
trong DoSomething
:
public static void DoSomething (string param1, string param2, SomeObject o, object someObjectLock)
{
//.....
lock(someObjectLock)
{
o.Things.Add(param1);
o.Update();
// etc....
}
}
.210
Variant C: Tạo thuộc tính
SyncRoot Nếu bạn có thể kiểm soát việc thực hiện các SomeObject
, nó có thể là thuận tiện để cung cấp các đối tượng khóa như một tài sản. Bằng cách đó, bạn có thể thực hiện biến thể B mà không cần phải vượt qua xung quanh một tham số thứ hai:
class SomeObject
{
private readonly object syncRoot = new object();
public object SyncRoot { get { return syncRoot; } }
...
}
Sau đó, bạn chỉ cần sử dụng lock(o.SyncRoot)
trong DoSomething
. Đó là mô hình một số lớp BCL sử dụng, ví dụ: Array.SyncLock, ICollection.SyncRoot.
Tôi tin rằng 'doSomethingLock' thường được gọi là' syncRoot'. – Sung
Tôi nghĩ rằng tôi thấy tại sao bây giờ. Tôi không thể khóa tham chiếu được chuyển cho phương thức vì bất kỳ ai sử dụng đối tượng đó cũng sẽ có thể khóa nó. Trong thực tế, nó giống như làm khóa (điều này) nhưng đến một lớp khác. – ghostJago
Các đối tượng khóa cũng phải là chỉ đọc. –