Trình lặp lại không an toàn và không nhanh trong Java là gì


101

Có hai loại trình vòng lặp trong Java: không an toàn và không nhanh.

Điều này có nghĩa là gì, và sự khác biệt giữa chúng là gì?


3
liên kết tốt nhất mà tôi tìm thấy javahungry.blogspot.com/2014/04/...
Premraj

2
Lưu ý rằng các thông số kỹ thuật của Java SE không sử dụng thuật ngữ "không an toàn" để mô tả bất kỳ trình vòng lặp nào. Do đó, tôi khuyên bạn nên tránh thuật ngữ này. Xem thêm stackoverflow.com/a/38341921/1441122
Stuart Marks

Câu trả lời:


84

Sự khác biệt giữa chúng là gì ...

"Không an toàn" ( trong kỹ thuật ) có nghĩa là một cái gì đó bị lỗi theo cách không gây ra hoặc ít thiệt hại. Nói một cách chính xác, trong Java không có thứ gì như là một trình lặp an toàn không thành công. Nếu một trình lặp không thành công (theo nghĩa thông thường là "fail"), bạn có thể mong đợi thiệt hại xảy ra.

Tôi nghi ngờ rằng bạn thực sự có nghĩa là trình vòng lặp "nhất quán yếu". Javadoc nói:

"Hầu hết các triển khai Bộ sưu tập đồng thời (bao gồm hầu hết các Hàng đợi) cũng khác với các quy ước java.util thông thường ở chỗ Trình lặp và Trình điều khiển của chúng cung cấp tính nhất quán yếu chứ không phải truyền tải nhanh."

Thông thường, tính nhất quán yếu có nghĩa là nếu một tập hợp được sửa đổi đồng thời với một lần lặp, thì sự đảm bảo về những gì mà phép lặp nhìn thấy sẽ yếu hơn. (Chi tiết sẽ được chỉ định trong từng lớp thu thập đồng thời javadocs.)

"Không nhanh" ( trong thiết kế hệ thống ) có nghĩa là tình trạng lỗi được kiểm tra tích cực để tình trạng lỗi là (nếu có thể 1 phát hiện ) trước khi có thể thực hiện quá nhiều hư hỏng. Trong Java, một trình lặp không nhanh không thành công bằng cách ném một ConcurrentModificationException.

Sự thay thế cho "không nhanh chóng" và "nhất quán yếu" là về mặt ngữ nghĩa mà sự lặp lại không thể đoán trước được; ví dụ đôi khi đưa ra câu trả lời sai hoặc đưa ra một ngoại lệ không mong muốn. (Đây là hành vi của một số triển khai tiêu chuẩn của EnumerationAPI trong các phiên bản Java đầu tiên.)

... và chúng khác với trình lặp mà chúng tôi sử dụng để thu thập.

Không. Đây là các thuộc tính của trình vòng lặp được thực hiện bởi các loại Bộ sưu tập tiêu chuẩn; tức là chúng "không nhanh" hoặc "nhất quán yếu" ... khi được sử dụng đúng cách liên quan đến đồng bộ hóa và mô hình bộ nhớ Java 1 .


Các trình vòng lặp không nhanh thường được triển khai bằng cách sử dụng bộ volatileđếm trên đối tượng thu thập.

  • Khi bộ sưu tập được cập nhật, bộ đếm sẽ tăng lên.
  • Khi một Iteratorđược tạo, giá trị hiện tại của bộ đếm được nhúng vào Iteratorđối tượng.
  • Khi một Iteratorthao tác được thực hiện, phương thức này sẽ so sánh hai giá trị bộ đếm và ném CME nếu chúng khác nhau.

Ngược lại, các trình vòng lặp nhất quán yếu thường là các thuộc tính trọng lượng nhẹ và đòn bẩy của từng cấu trúc dữ liệu nội bộ của bộ sưu tập đồng thời. Không có khuôn mẫu chung. Nếu bạn quan tâm, hãy đọc mã nguồn cho các lớp thu thập khác nhau.


1 - Người lái là hành vi không nhanh giả định rằng id ứng dụng chính xác liên quan đến đồng bộ hóa và mô hình bộ nhớ. Điều đó có nghĩa là (ví dụ) nếu bạn lặp lại một ArrayListmà không đồng bộ hóa thích hợp, kết quả có thể là kết quả danh sách bị hỏng. Cơ chế "lỗi nhanh" có thể sẽ phát hiện sửa đổi đồng thời (mặc dù điều đó không được đảm bảo), nhưng nó sẽ không phát hiện ra tham nhũng cơ bản. Ví dụ, javadoc cho Vector.iterator()biết điều này:

"Các hành vi thất bại nhanh của một iterator không được đảm bảo như nó có, nói chung, không thể thực hiện bất kỳ đảm bảo cứng trong sự hiện diện của đồng thời sửa đổi không đồng bộ. Lặp Fail nhanh ném ConcurrentModificationExceptiontrên cơ sở nỗ lực tốt nhất. Vì vậy, nó sẽ là sai khi viết một chương trình phụ thuộc vào ngoại lệ này vì tính đúng đắn của nó: hành vi không nhanh của trình vòng lặp chỉ nên được sử dụng để phát hiện lỗi. "


Có thể một chút không liên quan nhưng cũng có thể bổ sung cho câu hỏi này. Còn về kiểu chụp nhanh được sử dụng bởi CoW chẳng hạn? Cụ thể hơn, tôi không hiểu rõ về cách mảng bên dưới (hoặc ảnh chụp nhanh) mà trình lặp CoW lặp lại "không bao giờ" thấy bất kỳ thay đổi nào được thực hiện bởi các luồng khác vì chúng tôi vẫn có thể gọi setArraybất kỳ sửa đổi nào.
stdout

Tôi quyết định rằng việc nói về việc triển khai các trình vòng lặp nhất quán yếu nằm ngoài phạm vi của phần Hỏi & Đáp này.
Stephen C

42

Chúng là các loại khá nhanhkhông nhất quán :

Trình lặp từ lần java.utilném góiConcurrentModificationException nếu bộ sưu tập được sửa đổi bởi các phương thức của bộ sưu tập (thêm / xóa) trong khi lặp

Các trình lặp từ java.util.concurrentgói thường lặp lại qua một ảnh chụp nhanh và cho phép các sửa đổi đồng thời nhưng có thể không phản ánh cập nhật bộ sưu tập sau khi trình lặp được tạo.


Iterator là ví dụ về thất bại nhanh trong khi liệt kê là không an toàn
Ajay Sharma

5
@AjaySharma - Không chính xác về hai số lượng. 1) Không Iteratorhoặc Enumerationchỉ định hành vi là không nhanh hoặc không an toàn. Chính các triển khai cụ thể (tức là các phương thức collection iterator()/ elements()etc cụ thể trả về các đối tượng này) xác định hành vi. 2) Việc triển khai Bảng kê điển hình không nhanh hoặc không an toàn .
Stephen C

22

Sự khác biệt duy nhất là trình lặp không an toàn không ném ra bất kỳ Ngoại lệ nào, trái với Trình lặp nhanh không thành công.

Nếu Bộ sưu tập được sửa đổi về cấu trúc trong khi một luồng đang lặp lại nó. Điều này là do chúng hoạt động trên bản sao của Bộ sưu tập thay vì bộ sưu tập gốc và đó là lý do tại sao chúng được gọi là trình lặp an toàn không thành công.

Trình lặp của CopyOnWriteArrayList là một ví dụ về lặp lại không an toàn, Trình lặp cũng được viết bởi ConcurrentHashMap keySet cũng là trình lặp không an toàn và không bao giờ ném ConcurrentModificationException trong Java.


Tôi không thấy ConcurrentHashMap iterator đang làm việc trên clone () .. :( Một số lần nó sẽ phản ánh một số cập nhật trong khi iterating ..
Kanagavelu Sugumar

0

Kịch bản này liên quan đến "xử lý đồng thời", có nghĩa là nhiều người dùng truy cập vào cùng một tài nguyên. Trong tình huống như vậy, một trong những người dùng cố gắng sửa đổi tài nguyên đó gây ra 'ConcurrentProcessingException' vì trong trường hợp đó người dùng khác nhận được dữ liệu không phù hợp. Cả hai loại này đều liên quan đến loại tình huống này.

Nói một cách dễ hiểu,

Không nhanh:

  • Các trình lặp ngay lập tức ném ConcurrentModificationException nếu sửa đổi cấu trúc (thêm, cập nhật, xóa) xảy ra.
  • Ví dụ: ArrayList, HashMap, TreeSet

Không an toàn:

  • Ở đây, các Trình lặp lại không ném ra bất kỳ ngoại lệ nào vì chúng hoạt động trên bản sao của bộ sưu tập, không phải bản gốc. Vì vậy, chúng là các trình vòng lặp không an toàn.
  • Ví dụ: CopyOnWriteArrayList, ConcurrentHashMap
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.