2011-07-06 27 views
8

Khi tôi thực hiện đoạn mã sau, tôi nhận được ConcurrentModificationExceptionJava: ConcurrentModificationException khi iterating trên danh sách

Collection<String> myCollection = Collections.synchronizedList(new ArrayList<String>(10)); 
    myCollection.add("123"); 
    myCollection.add("456"); 
    myCollection.add("789"); 
    for (Iterator it = myCollection.iterator(); it.hasNext();) { 
     String myObject = (String)it.next(); 
     System.out.println(myObject); 
     myCollection.remove(myObject); 
     //it.remove(); 
    } 

Tại sao tôi lại nhận được ngoại lệ, mặc dù tôi đang sử dụng Collections.synchronizedList?

Khi tôi thay đổi myCollection để

ConcurrentLinkedQueue<String> myCollection = new ConcurrentLinkedQueue<String>(); 

Tôi không nhận được ngoại lệ đó.

ConcurrentLinkedQueue trong java.util.concurrent khác với Collections.synchronizedList như thế nào?

+0

Bản sao có thể có của [Iterating through a Collection, tránh ConcurrentModificationException khi loại bỏ trong vòng lặp] (http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re) – Raedwald

Trả lời

13

A đồng bộ Danh sách sẽ không cung cấp triển khai mới Iterator. Nó sẽ sử dụng việc triển khai danh sách được đồng bộ hóa. Các implementation của iterator() là:

public Iterator<E> iterator() { 
    return c.iterator(); // Must be manually synched by user! 
} 

Từ ArrayList:

các vòng lặp được trả về bởi iterator và listIterator phương pháp của lớp này là thất bại nhanh: nếu danh sách được cấu trúc biến đổi bất cứ lúc nào sau khi Trình tạo lặp được tạo, theo bất kỳ cách nào ngoại trừ thông qua các phương thức loại bỏ hoặc thêm của trình lặp, thì trình vòng lặp sẽ ném một số ConcurrentModificationException

Từ ConcurrentLinkedQueue#iterator:

Trả về trình lặp qua các phần tử trong hàng đợi này theo đúng trình tự. Trình lặp trở lại là một bộ lặp "yếu nhất quán" sẽ không bao giờ ném ConcurrentModificationException và đảm bảo cho các phần tử đi qua khi chúng tồn tại khi xây dựng trình lặp và có thể (nhưng không được bảo đảm) phản ánh bất kỳ sửa đổi nào sau khi xây dựng.

Các trình vòng lặp được trả về bởi hai bộ sưu tập là khác nhau theo thiết kế.

7

không làm

myCollection.remove(myObject); 

làm

it.remove(); 

Không cần để đồng bộ hóa hoặc bộ sưu tập đồng thời

+0

My câu hỏi là, cả hai khác nhau như thế nào? – vinoth

+0

@cmv, nó không liên quan gì đến danh sách của bạn. nó có tất cả mọi thứ để làm với bạn cố gắng để sửa đổi một bộ sưu tập trong khi lặp qua nó. ['Iterator.remove()'] (http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html#remove%28%29) cho phép bạn làm điều này. – mre

+0

Tôi có nghĩa là, không Collections.synchronizedList chăm sóc làm cho hoạt động nguyên tử ..? – vinoth

2

thế nào là ConcurrentLinkedQueue trong java.util.concurrent khác nhau từ bộ sưu tập .synchronizedList?

Chúng có các triển khai khác nhau và do đó có thể chọn có ném đồng thời ConcurrentModificationException hay để xử lý tình huống bạn mô tả một cách duyên dáng. Rõ ràng CLQ xử lý một cách duyên dáng, và ArrayList được bao bọc bởi Collections.synchronizedList (tôi đoán là hành vi của ArrayList, không phải của trình bao bọc) thì không.

Như @unbeli nói, xóa qua trình lặp, không phải bộ sưu tập trong khi lặp lại.

Các vấn đề liên quan