Các luồng phương thức tĩnh không đồng bộ có an toàn không nếu chúng không sửa đổi các biến lớp tĩnh?


145

Tôi đã tự hỏi nếu bạn có một phương thức tĩnh không được đồng bộ hóa, nhưng không sửa đổi bất kỳ biến tĩnh nào thì nó có an toàn cho luồng không? Điều gì về nếu phương thức tạo các biến cục bộ bên trong nó? Ví dụ, mã sau đây có an toàn không?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

Vì vậy, nếu tôi có hai luồng gọi phương thức ths liên tục và đồng thời, một với chó (nói "tuyệt vời" và "chó bull") và hai với mèo (nói "Ba Tư" và "siamese") tôi sẽ không bao giờ có được mèo và chó trong cùng một mảng? Hay những con mèo và con chó sẽ không bao giờ ở trong cùng một lời mời của phương pháp cùng một lúc?


một chủ đề khác về vấn đề này: stackoverflow.com/questions/8015797/ Cách
象 嘉

2
Đó là một câu hỏi khác nhau, đây là liệu việc gọi phương thức tĩnh có an toàn cho luồng không, có phải là mảng không.
Sled

Câu trả lời:


212

Phương pháp này là 100% luồng an toàn, nó sẽ thậm chí nếu không static. Vấn đề với an toàn luồng phát sinh khi bạn cần chia sẻ dữ liệu giữa các luồng - bạn phải quan tâm đến tính nguyên tử, khả năng hiển thị, v.v.

Phương thức này chỉ hoạt động trên các tham số, nằm trên stack và tham chiếu đến các đối tượng bất biến trên heap. Stack vốn là cục bộ của luồng , vì vậy không bao giờ chia sẻ dữ liệu.

Các đối tượng không thay đổi ( Stringtrong trường hợp này) cũng an toàn cho luồng vì một khi được tạo, chúng không thể thay đổi và tất cả các luồng đều nhìn thấy cùng một giá trị. Mặt khác, nếu phương thức được chấp nhận (có thể thay đổi), Datebạn có thể đã gặp sự cố. Hai luồng có thể đồng thời sửa đổi cùng một đối tượng, gây ra các điều kiện chủng tộc và các vấn đề về tầm nhìn.


4
Câu trả lời chính xác. Các biến mức phương thức được sao chép trong mỗi ngăn xếp thực thi luồng.
Sid

về mặt kỹ thuật, phương pháp sẽ được nội tuyến và các tham số sẽ là các thanh ghi CPU. Tuy nhiên, câu trả lời là chính xác
bestsss

43
Ngăn xếp tất nhiên là cục bộ của luồng hiện tại, nhưng bạn có thể có các tham chiếu đến các đối tượng được chia sẻ trên ngăn xếp đó. Đây không phải là một vấn đề trong ví dụ vì Chuỗi là bất biến, nhưng một phương thức sửa đổi một tham số đã truyền có thể có các vấn đề an toàn luồng nếu đối tượng được truyền này có thể truy cập được từ nhiều luồng.
Jorn Horstmann

1
Như @TomaszNurkiewicz đã đề cập, nếu chúng ta vượt qua một tham chiếu đối tượng có thể thay đổi, chúng ta có thể rơi vào điều kiện cuộc đua. Điều này có đúng ngay cả khi phương thức không thay đổi đối tượng theo bất kỳ cách nào không? Ý tôi là, nó vẫn sẽ được phân loại là một điều kiện chủng tộc bởi vì đối tượng là có thể thay đổi? Và nếu chúng ta thêm từ khóa cuối cùng vào các tham số thì sao?
Rafay

Điều gì xảy ra nếu tôi truyền đối tượng lớp trong phương thức? Sự thay đổi trong ngăn xếp hoặc đống?
grep

28

Một phương thức chỉ có thể không an toàn cho luồng khi nó thay đổi một số trạng thái chia sẻ. Cho dù đó là tĩnh hay không là không liên quan.


3
@Konrad_Garus Câu hỏi ở đây nằm dọc theo dòng liệu các biến cục bộ có tạo thành trạng thái chia sẻ hay không, hoặc liệu ngăn xếp cho một phương thức tĩnh là trên mỗi luồng hoặc được chia sẻ.
Sled

"Một phương thức chỉ có thể không an toàn cho luồng khi nó thay đổi một số trạng thái chia sẻ." Không, nó cũng có thể là luồng không an toàn nếu nó chỉ truy cập trạng thái chia sẻ mà không thay đổi nó. Truy cập không đồng bộ vào một đối tượng có thể thay đổi có thể truy cập trạng thái không nhất quán nếu đối tượng đang bị đột biến bởi một luồng khác, ngay cả khi luồng khác được đồng bộ hóa đúng. Cả hai luồng cần đồng bộ hóa thích hợp để duy trì an toàn luồng.
Warren Dew

12

Các chức năng là hoàn toàn chủ đề an toàn.

Nếu bạn nghĩ về nó ... giả sử điều gì sẽ xảy ra nếu điều này khác đi. Mọi hàm thông thường sẽ có các vấn đề luồng nếu không được đồng bộ hóa, vì vậy tất cả các hàm API trong JDK sẽ phải được đồng bộ hóa, bởi vì chúng có thể được gọi bởi nhiều luồng. Và vì hầu hết thời gian ứng dụng đang sử dụng một số API, các ứng dụng đa luồng sẽ thực sự là không thể.

Điều này quá vô lý để nghĩ về nó, vì vậy chỉ dành cho bạn: Phương pháp không phải là chủ đề an toàn nếu có một lý do rõ ràng tại sao có thể có vấn đề. Cố gắng luôn nghĩ về điều gì sẽ xảy ra nếu có nhiều luồng trong chức năng của tôi và điều gì xảy ra nếu bạn có trình gỡ lỗi từng bước và sẽ tiến lên một bước khác trước ... sau đó là luồng thứ hai ... có thể là lần thứ hai ... sẽ có vấn đề? Nếu bạn tìm thấy một, nó không phải là chủ đề an toàn.

Cũng xin lưu ý rằng, hầu hết các lớp Bộ sưu tập Java 1.5 không phải là các luồng an toàn, ngoại trừ các lớp được nêu, như ConcảnHashMap.

Và nếu bạn thực sự muốn đi sâu vào vấn đề này, hãy xem xét kỹ từ khóa dễ bay hơi và TẤT CẢ các tác dụng phụ của nó. Hãy xem lớp Semaphore () và Lock () và bạn bè của họ trong java.util.Conc hiện. Đọc tất cả các tài liệu API xung quanh các lớp. Đó là giá trị để tìm hiểu và đáp ứng, quá.

Xin lỗi vì câu trả lời quá công phu này.


2
"Nếu bạn nghĩ về nó ... giả sử điều gì sẽ xảy ra nếu điều này khác đi. Mọi chức năng thông thường sẽ có vấn đề luồng nếu không được đồng bộ hóa, vì vậy tất cả các hàm API trong JDK sẽ phải được đồng bộ hóa, bởi vì chúng có thể được gọi bởi nhiều chủ đề. " Điểm tốt!
Sled

1

Sử dụng statictừ khóa với các phương thức tĩnh được đồng bộ hóa để sửa đổi dữ liệu tĩnh được chia sẻ giữa các luồng. Với statictừ khóa, tất cả các luồng được tạo sẽ tranh giành một phiên bản duy nhất của phương thức.

Sử dụng volatiletừ khóa cùng với các phương thức cá thể được đồng bộ hóa sẽ đảm bảo rằng mỗi luồng có bản sao riêng của dữ liệu được chia sẻ và không đọc / ghi sẽ bị rò rỉ giữa các luồng.


0

Các đối tượng chuỗi không thay đổi là một lý do khác cho kịch bản an toàn luồng ở trên. Thay vào đó, nếu các đối tượng có thể thay đổi được sử dụng (giả sử makeMutableArray ..) thì chắc chắn an toàn luồng sẽ bị phá vỡ.


Câu hỏi là nếu một cuộc gọi phương thức tĩnh sẽ bao giờ thấy các đối số của một cuộc gọi khác đến cùng một phương thức từ một luồng khác. Câu trả lời là không có vang dội!". Điều này, tôi biết nhưng muốn có thể chứng minh với đồng nghiệp đáng ngờ.
Sled

Tại sao phản ứng này đã bỏ phiếu? Điểm, không được đóng góp bởi các câu trả lời khác, là tính đột biến có thể bị ràng buộc hoặc bị ràng buộc. Nếu bạn trả về một biến đổi, thì bạn không phải là chủ đề an toàn. Câu hỏi không đặt ra câu hỏi của nó hẹp như nhận xét cho thấy; câu hỏi mở rộng sau khi mẫu mã có thể được thể hiện bằng mã, có lẽ là một bài kiểm tra đơn vị. Nhưng tôi thông cảm với việc cố gắng thuyết phục đồng nghiệp. "Họ không tin tôi, hoặc mã kiểm tra của tôi, hoặc Josh Bloch, nhưng có lẽ họ sẽ chấp nhận câu trả lời trên SO."
som-snytt
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.