2012-12-18 13 views
7

Tôi đang gọi hàm trả về trường hợp TreeMap và trong mã gọi điện tôi muốn sửa đổi TreeMap. Tuy nhiên, tôi đang nhận được ConcurrentModificationException.Tránh TreeMap ConcurrentModificationException?

Đây là mã của tôi:

public Map<String, String> function1() { 
    Map<String, String> key_values = Collections.synchronizedMap(new TreeMap<String, String>()); 
    // all key_values.put() goes here 

    return key_values; 
} 

Và mã gọi tôi là:

Map<String, String> key_values =Collections.synchronizedMap(Classname.function1()); 
//here key_values.put() giving ConcurrentModificationException 
+1

Tôi có thể hỏi điểm tạo Bản đồ đồng bộ từ bên trong hàm 1 không? Nó không được sử dụng bởi bất kỳ ai ngoài "mã gọi điện thoại" của bạn ... –

+0

cách bạn sửa đổi bản đồ? –

Trả lời

2

Nếu bạn sử dụng ConcurrentSkipListMap có thể nhanh hơn và không gặp phải vấn đề này.

public NavigableMap<String, String> function1() { 
    NavigableMap<String, String> key_values = new ConcurrentSkipListMap<String, String>(); 
    // all key_values.put() goes here 

    return key_values; 
} 

Nếu bạn không cần khóa để được sắp xếp, bạn có thể sử dụng ConcurrentHashMap.

+1

Có thể hữu ích khi hiểu danh sách bỏ qua * là gì: https://en.wikipedia.org/wiki/Skip_list –

13

Lưu ý rằng Collections.synchronizedMap sẽ không bao giờ bảo vệ bạn khỏi đồng thời sửa đổi nếu bạn đang sử dụng một iterator. Ngoài ra, trừ khi bạn đang truy cập vào Map từ nhiều hơn một luồng, việc tạo bản đồ đã đồng bộ hóa là vô ích. Bộ sưu tập và biến số cục bộ không được giao cho các chủ đề khác không cần phải là synchronized.

tôi đoán là trong đoạn code bạn bỏ qua, bạn đang lặp lại qua một trong Map.entrySet, Map.keySet, hoặc Map.values, và kêu gọi puttrong lặp đó (trong for loop). Với mã bạn đã hiển thị, đây là cách duy nhất điều này có thể xảy ra.

+0

Ya bạn r viết thưa ngài, đó là lỗi của tôi .. Cảm ơn –

1

Dường như bạn đang nhận bản đồ đồng bộ của bản đồ đã đồng bộ hóa. Nếu tôi thay thế các cuộc gọi đến Function1() với nội dung của nó (giản thể) ta có:

Map<String, String> key_values =Collections.synchronizedMap(Collections.synchronizedMap(new TreeMap<String, String>())); 

Tôi nghĩ rằng dòng gọi của bạn nên được thay đổi:

Map<String, String> key_values = Classname.function1(); 
+1

Không thực sự là một câu trả lời, vì vậy không +1, nhưng vẫn là một lưu ý tốt. – Brian

+0

@Brian Tôi nghĩ chi tiết này rất quan trọng. Bởi vì, với lớp bọc đôi này, anh ta sẽ không thể đồng bộ hóa trên đối tượng TreeMap thực tế mà anh ta cần nếu anh ta cố gắng lặp lại và cập nhật. –

1

Bạn đang tìm kiếm một MAP đồng bộ , vì vậy tôi cho rằng bạn đang xử lý một ứng dụng đa luồng. Trong trường hợp đó nếu bạn muốn sử dụng trình lặp, bạn phải đồng bộ khối cho MAP.

/*This reference will give error if you update the map after synchronizing values.*/ 
    Map<String, String> values =Collections.synchronizedMap(function1()); 

/*This reference will not give error if you update the map after synchronizing values */ 
     Map<String, String> values = Collections.synchronizedMap(new TreeMap<String, String>()); 


    synchronized (values) 
       {   
        Iterator it = values.entrySet().iterator(); 
        while(it.hasNext()) 
        { 
         it.next() ; 
    // You can update the map here.  
        } 
       } 

Cập nhật:

Trên thực tế trong trường hợp của bạn, xem xét err mà bạn đang gấp đôi gói MAP, sửa đổi nó trong vòng lặp while ngay cả với một khối đồng bộ sẽ đưa ra một ngoại lệ CM như bạn sẽ không thể đồng bộ hóa trên đối tượng MAP ban đầu đang bị udpated.