2009-11-21 25 views
16

Tôi hiểu rằng các bộ sưu tập như Hashtable được đồng bộ hóa, nhưng ai đó có thể giải thích cho tôi cách hoạt động của và tại thời điểm nào quyền truy cập bị hạn chế đối với các cuộc gọi đồng thời? Ví dụ: giả sử tôi sử dụng một số trình lặp như sau:Giải thích đồng bộ hóa các bộ sưu tập khi các trình vòng lặp được sử dụng?

Hashtable<Integer,Integer> map = new Hashtable<Integer,Integer>(); 

void dosomething1(){ 
    for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){ 
     // do something 
    } 
} 
void dosomething2(){ 
    for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){ 
     // do something 
     // and remove it 
     i.remove(); 
    } 
} 
void putsomething(int a, int b){ 
    map.put(a,b); 
} 
void removesomething(int a){ 
    map.remove(a); 
} 
var clear(){ 
    map = new Hashtable<Integer,Integer>(); 
} 

Ai đó có thể giải thích nếu có bất kỳ cạm bẫy nào khi tôi gọi các chức năng này ngẫu nhiên với các chủ đề khác nhau không? Làm thế nào để các iterator, đặc biệt, làm đồng bộ hóa của nó, đặc biệt là khi nó được sử dụng entrySet(), mà dường như cũng yêu cầu đồng bộ hóa? Điều gì sẽ xảy ra nếu clear() được gọi trong khi một trong các vòng lặp đang diễn ra? Điều gì sẽ xảy ra nếu removeomething() loại bỏ một mục chưa được xử lý bởi một vòng lặp đồng thời trong dosomething1()?

Cảm ơn bạn đã trợ giúp!

Trả lời

34

lặp qua các bộ sưu tập trong Java không phải là thread an toàn, ngay cả khi bạn đang sử dụng một trong những giấy gói đồng bộ (Collections.synchronizedMap(...)):

Điều bắt buộc là người sử dụng bằng tay đồng bộ hóa trên các trở bản đồ khi iterating trên bất kỳ quan điểm bộ sưu tập của mình:

Map m = Collections.synchronizedMap(new HashMap()); 
... 
Set s = m.keySet(); // Needn't be in synchronized block 
... 
synchronized(m) { // Synchronizing on m, not s! 
    Iterator i = s.iterator(); // Must be in synchronized block 
    while (i.hasNext()) 
     foo(i.next()); 
} 

Java Collection Framework docs

cuộc gọi khác vào bộ sưu tập đồng bộ được an toàn, như các lớp wrapper bao quanh chúng với synchronized khối, sử dụng bộ sưu tập wrapper như màn hình của họ:

public int size() { 
    synchronized(this) { 
     return collection.size(); 
    } 
} 

với collection là bộ sưu tập gốc. Điều này làm việc cho tất cả các phương thức được trưng ra bởi một bộ sưu tập/bản đồ, ngoại trừ các công cụ lặp lại.

Tập hợp khóa của bản đồ được thực hiện đồng bộ theo cách giống nhau: trình bao bọc đồng bộ không trả về bộ khóa gốc. Thay vào đó, nó trả về một wrapper được đồng bộ hóa đặc biệt của tập hợp khóa gốc của bộ sưu tập. Điều tương tự cũng áp dụng cho bộ mục nhập và giá trị được đặt.

+0

Cố định câu trả lời: màn hình được sử dụng thực sự là bộ sưu tập bao bọc, chứ không phải bộ sưu tập gốc. – Dirk

+0

Đó là siêu hữu ích và trình bày rất tốt. Tôi đã gặp khó khăn khi tìm một nguồn giải thích rõ ràng điều này, vì vậy cảm ơn rất nhiều! – DivideByHero

+0

"Lặp lại bộ sưu tập trong Java không phải là chủ đề an toàn, ngay cả khi bạn đang sử dụng một trong các trình bao bọc được đồng bộ" O_o khủng khiếp – rkarajan

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