簡體   English   中英

Android:Hashmap並發修改異常

[英]Android: Hashmap concurrent Modification Exception

我的代碼不斷出現並發修改異常。 我只是遍歷哈希圖並修改值。 通過研究,我發現人們說要使用iterators和iterator.remove等。我嘗試使用它進行實現,但仍然不斷出錯。 我以為可能有多個線程訪問了它? (盡管在我的代碼中,該塊僅在一個線程中運行),所以我將其放在同步塊中。 但是,我仍然遇到錯誤.....

 Map map= Collections.synchronizedMap(questionNumberAnswerCache);
        synchronized (map) {
            for (Iterator<Map.Entry<String, Integer>> it = questionNumberAnswerCache.entrySet().iterator(); it.hasNext(); ) {
                Map.Entry<String, Integer> entry = it.next();
                if (entry.getKey() == null || entry.getValue() == null) {
                    continue;
                } else {
                    try {
                        Question me = Question.getQuery().get(entry.getKey());
                        int i = Activity.getQuery()
                                .whereGreaterThan(Constants.kQollegeActivityCreatedAtKey, lastUpdated.get("AnswerNumberCache " + entry.getKey()))
                                .whereEqualTo(Constants.kQollegeActivityTypeKey, Constants.kQollegeActivityTypeAnswer)
                                .whereEqualTo(Constants.kQollegeActivityQuestionKey, me)
                                .find().size();

                        lastUpdated.put("AnswerNumberCache " + entry.getKey(), Calendar.getInstance().getTime());

                        int old_num = entry.getValue();
                        entry.setValue(i + old_num);

                    } catch (ParseException e) {
                        entry.setValue(0);
                    }
                }

            }

        }

錯誤:

  java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
        at java.util.HashMap$EntryIterator.next(HashMap.java:824)
        at java.util.HashMap$EntryIterator.next(HashMap.java:822)
        at com.juryroom.qollege_android_v1.QollegeCache.refreshQuestionAnswerNumberCache(QollegeCache.java:379)
        at com.juryroom.qollege_android_v1.QollegeCache.refreshQuestionCaches(QollegeCache.java:267)
        at com.juryroom.qollege_android_v1.UpdateCacheService.onHandleIntent(UpdateCacheService.java:28)
        at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.os.HandlerThread.run(HandlerThread.java:61)

怎么了:

迭代器遍歷地圖。 該地圖實際上並不像列表,因為它不關心順序。 因此,當您向地圖中添加某些內容時,它可能會插入到您已遍歷的對象的中間,中間的某個地方,最后等,所以它沒有給您隨機的行為,而是失敗了。

您的解決方案:

同步映射和同步塊允許您同時有兩個線程。 這實際上並沒有幫助,因為問題在於同一線程正在以非法方式對其進行修改。

您應該做什么:

您可以只保存要修改的密鑰。 除非這是一個非常關鍵的代碼段,否則用鍵和新值創建映射將不是問題。

然后,您只需遍歷newValues映射並更新oldValues映射。 由於您無需遍歷要更新的地圖,因此這不是問題。

或者,您可以僅通過鍵(對於String:yourMap)進行迭代,然后查找要更改的值。 由於您只是遍歷鍵,因此可以隨意更改值(但不能刪除值)。

您也可以嘗試使用ConcurrentHashMap,它應允許您對其進行修改,但是行為未定義,因此存在風險。 僅更改值不會導致問題,但是如果添加或刪除,則永遠不會知道它是否最終會被迭代。

創建一個對象並鎖定該對象-用腳射擊自己的好方法。

我建議使用以下代碼刪除哈希映射。

HashMap<Key, Object> hashMap = new HashMap<>();
LinkedList<Key> listToRemove = new LinkedList<>();
for(Map.Entry<Key, Object> s : hashMap.entrySet()) {
    if(s.getValue().equals("ToDelete")){
        listToRemove.add(s.getKey());
    }
}
for(Key s : listToRemove) {
    hashMap.remove(s);
}

它不是最美麗,最快的選擇,但它應該可以幫助您了解如何使用HashMap。

正如您將了解如何使用我的選擇。 您可以學習如何使用迭代器如何循環使用迭代器 (而不是簡單地復制粘貼)

Iterator it = tokenMap.keySet()) 
while(it.hasNext()) {
    if(/* some condition */) it.remove();
}

對於您的用例,我建議以下內容:

for(Key key : hashMap.keySet()) {
    Object value = hashMap.get(key);
    if(<condition>){
        hashMap.put(key, <new value>); 
}

如果您不刪除任何條目,而只是更改值,這應該對您有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM