Tác giả của ghi chú là Grzegorz Mirek, một nhà phát triển phần mềm đến từ Krakow (Ba Lan). Anh ấy bắt đầu phát triển Java khoảng 6 năm trước, khi vẫn còn học đại học và kể từ đó anh ấy đã không ngừng trau dồi kỹ năng của mình trong lĩnh vực này. Anh ấy đặc biệt quan tâm đến hiệu suất và tối ưu hóa JVM, đây là điều anh ấy chủ yếu viết trên blog của mình .
Một số câu hỏi phỏng vấn Java phổ biến nhất bao gồm: Sự khác biệt giữa các trình vòng lặp không nhanh và không an toàn là gì? Câu trả lời đơn giản nhất cho vấn đề này là: Một trình vòng lặp không nhanh sẽ ném ra một ngoại lệ ConcurrentModificationException nếu bộ sưu tập thay đổi trong quá trình lặp, nhưng một trình vòng lặp không an toàn thì không. Mặc dù điều này nghe có vẻ khá có ý nghĩa nhưng vẫn chưa rõ người phỏng vấn có ý gì khi nói không an toàn? Đặc tả ngôn ngữ Java không định nghĩa thuật ngữ này liên quan đến các trình vòng lặp. Tuy nhiên, có bốn chiến lược sửa đổi cạnh tranh.
Sửa đổi cạnh tranh
Trước tiên, hãy xác định sửa đổi cạnh tranh (hoặc song song) là gì. Giả sử chúng ta có một bộ sưu tập và khi trình vòng lặp hoạt động, một số thay đổi xảy ra không đến từ trình vòng lặp này. Trong trường hợp này, chúng tôi nhận được một sửa đổi cạnh tranh. Hãy để tôi cho bạn một ví dụ đơn giản: giả sử chúng ta có một số chủ đề. Luồng đầu tiên lặp lại và luồng thứ hai chèn hoặc xóa các phần tử khỏi cùng một bộ sưu tập. Tuy nhiên, chúng ta có thể gặp ConcurrentModificationException khi chạy trong môi trường đơn luồng:List<String> cities = new ArrayList<>();
cities.add(“Warsaw”);
cities.add(“Prague”);
cities.add(“Budapest”);
Iterator<String> cityIterator = cities.iterator();
cityIterator.next();
cities.remove(1);
cityIterator.next(); // генерирует ConcurrentModificationException
Thất bại nhanh chóng
Đoạn mã trên là một ví dụ về trình vòng lặp không nhanh . Như bạn có thể thấy, một ngoại lệ ConcurrentModificationException đã bị ném ra khi cố gắng truy xuất phần tử thứ hai từ iterator . Làm cách nào một trình vòng lặp biết rằng bộ sưu tập đã được sửa đổi kể từ khi nó được tạo? Ví dụ: bộ sưu tập có thể có dấu ngày/giờ, chẳng hạn như LastModified . Khi tạo một iterator, bạn nên sao chép trường này và lưu trữ nó trong một đối tượng iterator. Sau đó, mỗi lần bạn gọi phương thức next() , bạn sẽ chỉ so sánh giá trị LastModified từ bộ sưu tập với bản sao từ iterator. Ví dụ, một cách tiếp cận tương tự được sử dụng khi triển khai lớp ArrayList . Nó có một biến thể hiện modCount lưu trữ số lần danh sách đã được sửa đổi:final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Điều quan trọng cần lưu ý là các trình vòng lặp không nhanh hoạt động trên cơ sở tốt nhất, nghĩa là không có gì đảm bảo rằng ConcurrentModificationException sẽ được đưa ra trong trường hợp có một sửa đổi đồng thời. Vì vậy, bạn không nên dựa vào chúng - thay vào đó, chúng nên được sử dụng để phát hiện lỗi. Hầu hết các bộ sưu tập không đồng thời đều cung cấp các vòng lặp không nhanh .
Tính nhất quán yếu
Hầu hết các bộ sưu tập đồng thời trong gói java.util.concurrent (chẳng hạn như ConcurrentHashMap và hầu hết Queue ) đều cung cấp các trình vòng lặp có tính nhất quán yếu. Ý nghĩa của thuật ngữ này được giải thích rất rõ ràng trong tài liệu :- Chúng có thể được xử lý đồng thời với các hoạt động khác
- Họ không bao giờ ném ConcurrentModificationException
- Chúng được đảm bảo duyệt qua các phần tử hiện có tại thời điểm trình vòng lặp được tạo chính xác một lần và có thể (nhưng không bắt buộc) phản ánh các sửa đổi tiếp theo.
GO TO FULL VERSION