Phiên bản C # của từ khóa được đồng bộ hóa của java?


313

C # có phiên bản riêng của từ khóa "được đồng bộ hóa" không?

Tức là trong java, nó có thể được chỉ định cho một hàm, một đối tượng hoặc một khối mã, như vậy:

public synchronized void doImportantStuff() {
   // dangerous code goes here.
}

hoặc là

public void doImportantStuff() {
   // trivial stuff

   synchronized(someLock) {
      // dangerous code goes here.
   }
}

3
Các hình thức khối yêu cầu một tài liệu tham khảo để khóa. Trong dạng phương thức, đối tượng khóa hoàn toàn là cái này (hoặc Class [this. Class, không phải getClass ()] cho các phương thức tĩnh, nhưng không khóa trên Classes).
Tom Hawtin - tackline

1
Vẫn không được bảo vệ? Tôi luôn đến đây vì tôi không thể nhớ [MethodImpl(MethodImplOptions.Synchronized)]dòng đó .
Bitterblue 17/03 '

1
Tôi nghĩ đoạn mã thứ 2 của bạn sẽ không biên dịch - nó cần được đồng bộ hóa trên một cái gì đó.
PoweredByRice

Câu trả lời:


466

Đầu tiên - hầu hết các lớp sẽ không bao giờ cần phải an toàn cho luồng. Sử dụng YAGNI : chỉ áp dụng an toàn luồng khi bạn biết bạn thực sự sẽ sử dụng nó (và kiểm tra nó).

Đối với công cụ cấp phương thức, có [MethodImpl]:

[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}

Điều này cũng có thể được sử dụng trên các phụ kiện (thuộc tính và sự kiện):

private int i;
public int SomeProperty
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return i; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { i = value; }
}

Lưu ý rằng các sự kiện giống như trường được đồng bộ hóa theo mặc định, trong khi các thuộc tính được triển khai tự động thì không :

public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized

Cá nhân, tôi không thích việc thực hiện MethodImplvì nó khóa thishoặc typeof(Foo)- điều này trái với thực tiễn tốt nhất. Tùy chọn ưa thích là sử dụng ổ khóa của riêng bạn:

private readonly object syncLock = new object();
public void SomeMethod() {
    lock(syncLock) { /* code */ }
}

Lưu ý rằng đối với các sự kiện giống như trường, việc thực hiện khóa phụ thuộc vào trình biên dịch; trong các trình biên dịch cũ của Microsoft, nó là lock(this)/ lock(Type)- tuy nhiên, trong các trình biên dịch gần đây hơn, nó sử dụng cácInterlocked bản cập nhật - vì vậy an toàn cho luồng mà không có các phần khó chịu.

Điều này cho phép sử dụng chi tiết hơn và cho phép sử dụng Monitor.Wait/ Monitor.Pulseetc để giao tiếp giữa các luồng.

Một mục blog liên quan (sau này xem lại ).


@earcam và câu hỏi của bạn là? Câu nói đó là đúng. Phần lớn các lớp không có yêu cầu về an toàn luồng, sẽ không được kiểm tra về an toàn luồng và an toàn luồng sẽ ảnh hưởng đến hiệu suất. Số lượng các loại thực sự cần phải lo lắng về các chủ đề là rất ít - các bộ sưu tập, bộ ghép kênh được đồng bộ hóa có chủ ý, v.v.
Marc Gravell

4
Tôi nghĩ rằng tôi nên đã nói đơn giản; "Hầu hết các lớp sẽ không bao giờ cần phải an toàn cho luồng" nhưng "tất cả các nhà phát triển phải nhận biết đồng thời". Nhìn lại, tôi đồng ý rằng con số rất nhỏ (và chắc chắn là thứ bạn muốn nhận ngay tại một nơi, cho phép phần lớn các lớp tương tác không biết gì về môi trường xung quanh đa luồng của họ). Muốn tôi xóa bình luận nhanh hơn =)
Earcam

6
Bài đăng trên blog được liên kết của Marc có bản theo dõi vào tháng 3 năm 2010 nói rằng trong .NET 4.0 MethodImplvà các sự kiện giống như trường hiện tạo mã đồng bộ hóa tốt và không còn cần thiết phải sử dụng khóa riêng của bạn.
Rory O'Kane

2
Phần lớn các ứng dụng ngày nay đều dựa trên web, được phục vụ với các khung dựa trên việc tái sử dụng cá thể nặng và vòng đời đối tượng phức tạp thông qua việc tiêm phụ thuộc. Những suy nghĩ mặc định ngày nay có xu hướng sai lầm về mặt an toàn của luồng.
Sheepy

1
@Elazar bây giờ đã quá muộn, nhưng đối với bản ghi: thay đổi khung là thay đổi một dòng đối với họ csproj nếu bạn đã tạo nó bằng cách sử dụng các mẫu lõi .net tiêu chuẩn / .net - và .net thông thường có sẵn, như là đa nhắm mục tiêu. Tuy nhiên, công cụ IDE xung quanh điều này chỉ đơn giản là khủng khiếp - bạn chỉ cần biết những gì bạn có thể thay đổi và thành gì :)
Marc Gravell

56
static object Lock = new object();

lock (Lock) 
{
// do stuff
}

10
Bạn có chắc chắn muốn khai báo đối tượng khóa của mình là tĩnh ..?
serg10

21
Chắc chắn, vì vậy mọi Chủ đề có thể dễ dàng truy cập nó mà không cần chuyển các tài liệu tham khảo xung quanh.
Jan Gressmann

33
Nếu chúng ta đang ở trong bối cảnh câu hỏi của người hỏi, thì chúng ta đang nói về các phương thức cá thể. Sử dụng tĩnh có nghĩa là nếu luồng 1 gọi instance1.DoSthing () và luồng 2 gọi instance2.DoSthing, cuộc gọi thứ hai sẽ chặn ngay cả khi đó là một đối tượng hoàn toàn khác. Cuộc gọi của thread2 không nên chặn trừ khi ai đó đang gọi DoS Something trên cùng một đối tượng . Không nói bạn sai, nhưng nói rằng điều quan trọng là phải hiểu tác động của việc sử dụng tĩnh ở đây, bởi vì nó có thể gây ra hiệu suất kém bằng cách chặn toàn cầu thay vì trên cơ sở từng trường hợp.
AaronLS

1
@AaronLS Khóa tĩnh nếu rất hữu ích khi đối tượng của bạn thực hiện các hành động trên phạm vi lớn hơn chính nó. Luôn luôn xảy ra với các dịch vụ web chẳng hạn.
Thibault D.

4
-1 vì đây là hành vi khác với OP yêu cầu. Đây là một khóa lớp, không phải là một khóa cá thể.
chào

39

C # có phiên bản riêng của từ khóa "được đồng bộ hóa" không?

Không. Trong C #, bạn rõ ràng locktài nguyên mà bạn muốn làm việc trên các luồng không đồng bộ. lockmở một khối; nó không hoạt động ở cấp độ phương thức.

Tuy nhiên, cơ chế cơ bản là tương tự vì lockhoạt động bằng cách gọi Monitor.Enter(và sau đó Monitor.Exit) trên thời gian chạy. Java hoạt động theo cách tương tự, theo các tài liệu Sun .


3
Nó không có "từ khóa" tương đương, nhưng như câu trả lời của Marc Gravell ở trên cho thấy, bạn có thể đồng bộ hóa ở cấp phương thức bằng cách sử dụng chú thích [MethodImpl (MethodImplOptions.Synyncized)].
MindJuice

1
synchronizedphương thức của Java về cơ bản synchronized (this.getClass())sẽ không giống với C # lock(typeof(this))?
Sri Harsha Chilakapati

2
@SriHarshaChilakapati chỉ đúng một phần, synchronizedtừ khóa của java về một phương thức giống như : synchronized(this), chỉ trên một phương thức tĩnh mà nó hoạt động như thế nào synchronized(class).
bvdb

6

Hãy lưu ý, với các đường dẫn đầy đủ dòng: [MethodImpl(MethodImplOptions.Synchronized)]sẽ giống như

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]


1
hoặc bạn chỉ có thể sử dụngusing System.Runtime.CompilerServices;
aloisdg chuyển đến codidact.com

Tôi đã viết nhận xét đó khi tôi chưa biết về việc tự động chèn bằng cách sử dụng các câu lệnh, sau khi đã lập trình C # không quá vài ngày hoặc vài tuần và tôi rất ngạc nhiên về 3 lần nâng cấp đó.
Traubenfuchs

1
Bạn đã giúp ít nhất 3 nhà phát triển và điều đó thật tuyệt :)
aloisdg chuyển đến codidact.com

5

Bạn có thể sử dụng locktuyên bố thay thế. Tôi nghĩ rằng điều này chỉ có thể thay thế phiên bản thứ hai. Ngoài ra, hãy nhớ rằng cả hai synchronizedlockcần phải hoạt động trên một đối tượng.

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.