日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用迭代器时如何避免ConcurrentModificationException

發(fā)布時(shí)間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用迭代器时如何避免ConcurrentModificationException 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Java Collection類是快速失敗的,這意味著如果在使用迭代器遍歷某個(gè)線程的同時(shí)更改了Collection,則iterator.next()將拋出ConcurrentModificationException 。

在多線程以及單線程環(huán)境下都可能出現(xiàn)這種情況。

讓我們通過以下示例探索這種情況:

import java.util.*;public class IteratorExample {public static void main(String args[]){List<String> myList = new ArrayList<String>();myList.add("1");myList.add("2");myList.add("3");myList.add("4");myList.add("5");Iterator<String> it = myList.iterator();while(it.hasNext()){String value = it.next();System.out.println("List Value:"+value);if(value.equals("3")) myList.remove(value);}Map<String,String> myMap = new HashMap<String,String>();myMap.put("1", "1");myMap.put("2", "2");myMap.put("3", "3");Iterator<String> it1 = myMap.keySet().iterator();while(it1.hasNext()){String key = it1.next();System.out.println("Map Value:"+myMap.get(key));if(key.equals("2")){myMap.put("1","4");//myMap.put("4", "4");}}} }

輸出為:

List Value:1 List Value:2 List Value:3 Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)at java.util.AbstractList$Itr.next(AbstractList.java:343)at com.journaldev.java.IteratorExample.main(IteratorExample.java:27)

從輸出堆棧跟蹤中可以明顯看出,當(dāng)我們調(diào)用迭代器next()函數(shù)時(shí),異常即將到來。 如果您想知道Iterator如何檢查修改,則它的實(shí)現(xiàn)存在于AbstractList類中,其中定義了一個(gè)int變量modCount,該變量提供了更改列表大小的次數(shù)。 該值在每個(gè)next()調(diào)用中使用,以檢查功能checkForComodification()中是否有任何修改。

現(xiàn)在,注釋列表部分并再次運(yùn)行程序。

輸出將是:

Map Value:3 Map Value:2 Map Value:4

由于我們正在更新myMap中的現(xiàn)有鍵值,因此其大小沒有更改,并且沒有收到ConcurrentModificationException。 請(qǐng)注意,輸出結(jié)果可能在您的系統(tǒng)中有所不同,因?yàn)镠ashMap鍵集的排序方式與列表不同。 如果您將在HashMap中添加新鍵值的語句取消注釋,則會(huì)導(dǎo)致ConcurrentModificationException。

要在多線程環(huán)境中避免ConcurrentModificationException:

1.您可以將列表轉(zhuǎn)換為數(shù)組,然后在數(shù)組上進(jìn)行迭代。 這種方法適用于中小型列表,但是如果列表很大,則對(duì)性能的影響很大。

2.您可以通過將列表放在同步塊中來在鎖定時(shí)鎖定列表。 不建議使用此方法,因?yàn)樗鼘⑼V苟嗑€程的好處。

3.如果您使用的是JDK1.5或更高版本,則可以使用ConcurrentHashMap和CopyOnWriteArrayList類。 這是推薦的方法。

要在單線程環(huán)境中避免ConcurrentModificationException:

您可以使用迭代器remove()函數(shù)從基礎(chǔ)集合對(duì)象中刪除該對(duì)象。 但是在這種情況下,您可以從列表中刪除同一對(duì)象,而不能刪除任何其他對(duì)象。

讓我們使用并發(fā)集合類運(yùn)行示例:

package com.journaldev.java;import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList;public class ThreadSafeIteratorExample {public static void main(String[] args) {List<String> myList = new CopyOnWriteArrayList<String>();myList.add("1");myList.add("2");myList.add("3");myList.add("4");myList.add("5");Iterator<String> it = myList.iterator();while(it.hasNext()){String value = it.next();System.out.println("List Value:"+value);if(value.equals("3")){myList.remove("4");myList.add("6");myList.add("7");}}System.out.println("List Size:"+myList.size());Map<String,String> myMap = new ConcurrentHashMap<String,String>();myMap.put("1", "1");myMap.put("2", "2");myMap.put("3", "3");Iterator<String> it1 = myMap.keySet().iterator();while(it1.hasNext()){String key = it1.next();System.out.println("Map Value:"+myMap.get(key));if(key.equals("1")){myMap.remove("3");myMap.put("4", "4");myMap.put("5", "5");}}System.out.println("Map Size:"+myMap.size());}}

輸出為:

List Value:1 List Value:2 List Value:3 List Value:4 List Value:5 List Size:6 Map Value:1 Map Value:null Map Value:4 Map Value:2 Map Size:4

從上面的示例可以清楚地看出:

1.可以修改Concurrent Collection類,避免ConcurrentModificationException 。

2.對(duì)于CopyOnWriteArrayList ,迭代器不適應(yīng)列表中的更改,并且可以處理原始列表。

3.對(duì)于ConcurrentHashMap ,其行為并不總是相同的。

條件:

if(key.equals("1")){myMap.remove("3");

輸出為:

Map Value:1 Map Value:null Map Value:4 Map Value:2 Map Size:4

它正在使用添加了鍵“ 4”的新對(duì)象。 但不是下一個(gè)添加的鍵為“ 5”的對(duì)象。

現(xiàn)在,如果我將條件更改為

if(key.equals("3")){myMap.remove("2");

輸出為:

Map Value:1 Map Value:3 Map Value:null Map Size:4

在這種情況下,它不考慮新添加的對(duì)象。

因此,如果您使用的是ConcurrentHashMap,請(qǐng)避免添加新對(duì)象,因?yàn)榭梢愿鶕?jù)鍵集對(duì)其進(jìn)行處理。 請(qǐng)注意,同一程序可以在您的系統(tǒng)中打印不同的值,因?yàn)镠ashMap鍵集沒有任何順序。

額外的澆頭:

for(int i = 0; i<myList.size(); i++){System.out.println(myList.get(i));if(myList.get(i).equals("3")){myList.remove(i);i--;myList.add("6");} }

如果您正在單線程環(huán)境中工作,并且希望您的代碼處理列表中額外添加的對(duì)象,則可以使用以下代碼并避免使用迭代器。

請(qǐng)注意,由于要?jiǎng)h除同一對(duì)象,所以要減少計(jì)數(shù)器,如果必須刪除下一個(gè)或更遠(yuǎn)的對(duì)象,則不需要減少計(jì)數(shù)器。

自己嘗試。

參考:在JournalDev上 使用 JCG合作伙伴提供的迭代器時(shí)如何避免ConcurrentModificationException 。

    相關(guān)文章:

    • Java最佳實(shí)踐– Vector vs ArrayList vs HashSet
    • Java最佳實(shí)踐–隊(duì)列之戰(zhàn)和鏈接的ConcurrentHashMap
    • Java Fork / Join進(jìn)行并行編程
    • ConcurrentLinkedHashMap v 1.0.1發(fā)布
    相關(guān)片段:
    • 阻塞隊(duì)列示例以執(zhí)行命令
    • 限制URL連接的信號(hào)量示例
    • 執(zhí)行命令的同步隊(duì)列示例
    • 更一般的等待/通知機(jī)制的CountDownLatch示例

    翻譯自: https://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的使用迭代器时如何避免ConcurrentModificationException的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。