Tại sao đối tượng khóa phải tĩnh?


112

Rất phổ biến khi sử dụng một đối tượng chỉ đọc tĩnh riêng tư để khóa trong đa luồng. Tôi hiểu rằng private làm giảm các điểm vào đối tượng khóa bằng cách thắt chặt việc đóng gói và do đó quyền truy cập vào những thứ cần thiết nhất.

Nhưng tại sao tĩnh?

private static readonly object Locker = new object();

Cuối cùng, trường chỉ được sử dụng trong lớp của tôi và tôi cũng có thể sử dụng trường này để thay thế:

private readonly object Locker = new object();

Có ý kiến ​​gì không?

CẬP NHẬT:

Như một ví dụ, tôi đã dán mã này (chỉ là một ví dụ). Tôi có thể sử dụng khóa tĩnh hoặc không tĩnh trên điều này và cả hai sẽ hoạt động tốt. Xem xét câu trả lời dưới đây, tôi có nên xác định tủ đồ của mình như thế này không? (Xin lỗi, tôi có một cuộc phỏng vấn vào tuần tới và cần biết mọi chi tiết :)

private readonly object Locker = new object();

Và đây là mã:

    private int _priceA;
    private int _priceB;
    private EventWaitHandle[] _waithandle;
    private readonly IService _service;

//ctor
public ModuleAViewModel(IService service)
    {
        _service = service;
        _modelA = new ModelA();
        _waithandle = new ManualResetEvent[2];
        _waithandle[0] = new ManualResetEvent(false);
        _waithandle[1] = new ManualResetEvent(false);
        LoadDataByThread();
    }


 private void LoadDataByThread()
        {
            new Thread(() =>
                           {
                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceA = _service.GetPriceA();
                                   }
                                   _waithandle[0].Set();
                               }).Start();

                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceB = _service.GetPriceB();
                                   }
                                   _waithandle[1].Set();
                               }).Start();

                               WaitHandle.WaitAll(_waithandle);
                               PriceA = _priceA;
                               PriceB = _priceB;
                           }).Start();
        }

Cảm ơn


15
Theo hiểu biết của tôi, static thường được sử dụng để làm cho nó trở thành trường hợp bất khả tri. Nếu một số phiên bản "MyWorkerClass" tồn tại, thì chỉ một phiên bản có thể chạy với dữ liệu đã cho tại một thời điểm (giả sử tất cả chúng đều sử dụng tài nguyên được chia sẻ).
Brad Christie

2
Bản chỉnh sửa thiếu một chi tiết quan trọng: ở đâu _service_waithandlenằm ở đâu? ví dụ? tĩnh không? khác? Đó có thể , ví dụ, hãy cố ý đồng bộ hóa quyền truy cập vào một máy chủ từ xa ...
Marc Gravell

đúng, với lần chỉnh sửa thứ hai: vâng, từ phần cuối này, bạn có thể khóa từng trường hợp. Tuy nhiên, có thể có lý do để làm cho nó tĩnh - nếu nhà phát triển ban đầu muốn (như đã đề cập) đồng bộ hóa quyền truy cập để máy chủ chỉ nhận một yêu cầu cùng một lúc từ AppDomain này ... Tôi không thể biết liệu đó có phải là trường hợp không , hay đó chỉ là tình cờ.
Marc Gravell

Câu trả lời:


177

Nó không phải là "rất phổ biến khi sử dụng một đối tượng chỉ đọc tĩnh riêng tư để khóa trong đa luồng" - đúng hơn, người ta thường sử dụng một khóa ở mức độ chi tiết thích hợp / được chọn . Đôi khi đó là static. Thông thường hơn, IMO, nó không phải là - nhưng dựa trên ví dụ .

Thời gian chính bạn thấy statickhóa là đối với bộ nhớ cache toàn cầu hoặc để tải chậm dữ liệu / đĩa đơn toàn cầu. Và sau này, có nhiều cách tốt hơn để làm điều đó nào .

Vì vậy, nó thực sự phụ thuộc: làm thế nào được Lockersử dụng trong kịch bản của bạn? Có phải nó đang bảo vệ một thứ mà bản thân nó là tĩnh? Nếu vậy, khóa phải tĩnh. Nếu nó đang bảo vệ một cái gì đó dựa trên phiên bản, thì IMO khóa cũng phải dựa trên phiên bản.


24
Bạn có thể cung cấp thêm chi tiết về cách tốt hơn để tải chậm dữ liệu toàn cầu không?
bizi,

Tôi luôn sử dụng static / variable bởi vì nếu có một số nơi mà nó dựa trên phiên bản, tôi vẫn muốn kiểm soát phương thức / biến của mình đang được truy cập theo cách an toàn. Nhiều trường hợp có thể đang truy cập cùng một tài nguyên và tôi muốn kiểm soát điều đó. tôi cũng muốn thấy điều này tốt hơn. Bạn có một đại diện tuyệt vời và tôi chắc chắn rằng câu trả lời của bạn sẽ tuyệt vời không kém để tôi áp dụng. Xin hãy trả lời?
Andrew Simpson

82

Nó không nhất thiết phải tĩnh, trên thực tế, đôi khi nó không nên nên tĩnh.

Biến phải nằm trong cùng phạm vi với các phương thức mà bạn sử dụng để khóa. Nếu các phương thức là tĩnh, thì biến phải tĩnh và nếu các phương thức là phương thức cá thể, thì biến đó phải là một biến thể cá thể.

Một biến tĩnh sẽ vẫn hoạt động khi được sử dụng để khóa trong một phương thức thể hiện, nhưng sau đó bạn sẽ khóa quá nhiều. Bạn sẽ khóa tất cả các phương thức trong tất cả các trường hợp, không chỉ các phương thức trong cùng một trường hợp.


28
+1 cho "a-ha" ... Bạn sẽ khóa tất cả các phương thức trong tất cả các trường hợp, không chỉ các phương thức trong cùng một trường hợp.
radarbob

3
@radarbob - Chi tiết nhỏ: Bạn sẽ không khóa tất cả các phương thức mà bạn chỉ thực hiện một khóa mà nhiều khách hàng hơn có thể quan tâm. Các phương thức không bao giờ bị khóa, chỉ là mutex đã được sử dụng.
Erno

Tôi nghi ngờ việc diễn đạt câu trả lời này có thể gây hiểu lầm - việc khóa không cần phải làm gì với phạm vi các phương thức - nó chỉ nên quan tâm đến phạm vi dữ liệu được chia sẻ được truy cập trong các phương thức đó. Phương thức phiên bản có thể không truy cập bất kỳ dữ liệu được chia sẻ nào (và do đó không cần khóa), có thể truy cập dữ liệu được chia sẻ tĩnh (và do đó cần khóa tĩnh, thay vào đó, cấu trúc lại cũng có thể là ý kiến ​​hay), tương tự đối với tĩnh ...
Alexei Levenkov

@AlexeiLevenkov: Bạn nói đúng rằng phạm vi thực sự nên được quyết định bởi dữ liệu có tĩnh hay không, nhưng phạm vi của các phương pháp cũng nên được quyết định bởi điều đó, vì vậy tất cả đều khớp với nhau. Dữ liệu cá thể thường không cần khóa, nhưng nếu cá thể được chia sẻ giữa các luồng thì bạn sẽ cần khóa.
Guffa

28

Phạm vi và thời gian tồn tại của một khóa có thể / nên phụ thuộc vào 'thứ' bạn muốn khóa. Khóa tĩnh chủ yếu dùng để khóa những thứ tĩnh.


3
Chi tiết nhỏ: Khóa không tĩnh, đối tượng mà bạn sử dụng để xác định khóa là tĩnh. Một chi tiết nhỏ khác: Bạn không khóa "các thứ".
Guffa

2
Vâng, tôi nghĩ nếu chúng ta cố gắng khóa những "thứ" sai, chúng có thể quá lớn và mạnh, và một ngày nào đó sẽ thoát ra.
ProfK

12
@Guffa Đó của kỳ quặc, trong một chú thích ở trên, bạn nói đúng: "Bạn chỉ overcomplicating mọi thứ," bây giờ tôi nhìn thấy 1 phút trước khi nói rằng, có vẻ như bạn đã overcomplicating điều :)
Nicholas Petersen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.