2012-06-27 26 views
5

Tôi quan tâm nếu có bất kỳ khuôn khổ nào triển khai bộ sưu tập có hành vi sau.Bộ sưu tập Java để cho phép thêm và xóa trong khi đang lặp lại


Giả sử nó ban đầu bao gồm: [1, 2, 3]

  • Tôi lặp nó (sử dụng một iterator) và đạt được yếu tố 2, bây giờ tôi thêm 4 đến cùng (bộ sưu tập sẽ bây giờ là [1, 2, 3, 4]).
  • bây giờ tôi tạo ra một iterator mới và lặp bộ sưu tập, kết quả trong [1, 2, 3, 4]
  • tôi tiếp tục lặp lại với iterator đầu tiên và nó sẽ cho tôi chỉ 3 và trở
  • nay đặt lại trình lặp đầu tiên sẽ cho tôi [1, 2, 3, 4] (tương tự như tạo một cái mới).

Tương tự nên áp dụng cho việc xóa phần tử. Nếu tôi xóa 3 thay vì thêm, trình lặp thứ hai sẽ cho tôi [1, 2] trong khi người thứ nhất sẽ vẫn cho tôi 3 và kết thúc.


Vì vậy, khi tôi nhận được và iterator Tôi muốn nó cho tôi bộ sưu tập tôi đã có khi tôi tạo ra các iterator (ngay cả khi tôi lặp nó sau, ngày tôi lặp một chút và tiếp tục sau), khi tôi thiết lập lại iterator, nó sẽ thu thập rác, nó sẽ cập nhật lên phiên bản mới nhất và tôi có thể có nhiều phiên bản lặp được tạo vào các thời điểm khác nhau sẽ cung cấp các phiên bản khác nhau tùy thuộc vào nội dung của mảng khi trình vòng lặp được tạo.

Tôi cần nó hoạt động tốt với nhiều luồng và thích hợp hơn để triển khai hiệu quả.

Có ai biết về việc triển khai bộ sưu tập đó hay không hoặc tôi có phải tự mình triển khai không?

Trả lời

6

gì bạn mô tả trông rất giống với cách CopyOnWriteArrayList công trình:

  • khi bạn bắt đầu lặp lại, bạn có thể thay đổi bộ sưu tập (bao gồm từ thread khác) mà không ảnh hưởng đến sự lặp
  • nếu bạn tạo một iterator mới nó sẽ dựa trên bộ sưu tập đồng thời tạo
  • nó là chủ đề an toàn

Ví dụ đơn giản dưới đây với các outpu sau t:

Iterator 1-1
4 đã được thêm vào
Iterator 2-1
Iterator 2-2
Iterator 2-3
Iterator 2-4
Iterator 1-2
Iterator 1 - 3

public static void main(String[] args) throws InterruptedException { 
    final List<Integer> list = new CopyOnWriteArrayList<Integer>(); 
    list.addAll(Arrays.asList(1, 2, 3)); 
    new Thread(new Runnable() { 

     @Override 
     public void run() { 
      for (Integer i : list) { 
       System.out.println("Iterator 1 - " + i); 
       try { 
        Thread.sleep(10); 
       } catch (InterruptedException e) {} 
      } 
     } 
    }).start(); 
    Thread.sleep(10); 
    list.add(4); 
    System.out.println("4 has been added"); 
    for (Integer i : list) { 
     System.out.println("Iterator 2 - " + i); 
    } 

} 
+0

Tạo bản sao mới của bộ sưu tập về thay đổi (nội bộ)? Hay nó được thực hiện một cách hiệu quả hơn? – Razvi

+1

Có như mô tả trong javadoc: "tất cả các hoạt động đột biến (thêm, thiết lập, vv) được thực hiện bằng cách tạo một bản sao mới của mảng cơ bản." – assylias

+0

Hành vi này trông giống như những gì tôi cần. Nhưng bộ sưu tập sẽ có khá nhiều vật phẩm trong đó. Iterator được tạo ra thường xuyên trên nó, nhưng tôi tin rằng những thay đổi là hiếm hơn (vì vậy các bản sao trên thay đổi có thể không phải chịu quá nhiều tổn thất về hiệu năng). – Razvi

7

java.util.concurrent.CopyOnWriteArrayList sẽ hoạt động như thế này, ngoại trừ việc không có bộ sưu tập Java có "đặt lại" của trình lặp - nhưng nhận được trình lặp mới thay vì đặt lại có hiệu ứng bạn yêu cầu tại đây.

2

Bạn có thể sử dụng số ImmutableCollections từ thư viện ổi.

Danh sách ImmutableList được trả về thường xuyên - không phải lúc nào, nhưng thường là - chế độ xem liên tục trên không thay vì bản sao rõ ràng. Điều đó nói rằng, thông thường hơn thông thường của Danh sách - ví dụ: nó sẽ sử dụng các phương pháp chứa hiệu quả của bộ sưu tập sao lưu.

3

Bạn có thể tận dụng java.util.concurrent.CopyOnWriteArrayList<E>

Theo tài liệu:

Một thread-safe biến thể của ArrayList trong đó tất cả các hoạt động mutative (thêm, đặt, và vân vân) là được thực hiện bằng cách tạo một bản sao mới của mảng cơ bản .

An toàn chi phí nhưng an toàn.

Đây là thường quá tốn kém, nhưng có thể hiệu quả hơn lựa chọn thay thế khi hoạt động traversal bao la đông hơn đột biến, và rất hữu ích khi bạn không thể hoặc không muốn đồng bộ hóa traversals, nhưng cần phải loại trừ sự can thiệp trong số các chủ đề đồng thời. Phương thức iterator kiểu "snapshot" sử dụng tham chiếu đến trạng thái của mảng tại điểm mà trình vòng lặp được tạo.

Như lặp xảy ra trên một loại ảnh chụp, các hoạt động (remove, set, và add) trên Iterator bản thân không được hỗ trợ.

0

javolution có luồng an toàn Bản đồ nhanh

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