java 集合并發(fā)操作出現(xiàn)的異常ConcurrentModificationException
更新時間:2009年06月04日 02:31:12 作者:
Map在遍歷時候通常 現(xiàn)獲得其鍵值的集合Set,然后用迭代器Iterator來對Map進行遍歷。
如Java中的容器Map:
for(Person person : pList){
if(person.getGender()==Gender.MALE){
pList.remove(person); //不能在遍歷期間進行 remove這個操作
}
}
Map在遍歷時候通常 現(xiàn)獲得其鍵值的集合Set,然后用迭代器Iterator來對Map進行遍歷。
注意在遍歷的過程中,只能對Map中的元素進行相應的處理,不能把Map元素增加或者把Map元素減少,也就是說,不能改變Map的size大小,就會出現(xiàn)異常(不能在遍歷過程中修改刪除或者增加map中的元素)
報出的異常為 java.util.ConcurrentModificationException 異常
public class ConcurrentModificationExceptionextends RuntimeException
當方法檢測到對象的并發(fā)修改,但不允許這種修改時,拋出此異常。
例如,某個線程在 Collection 上進行迭代時,通常不允許另一個線性修改該 Collection。通常在這些情況下,迭代的結果是不明確的。如果檢測到這種行為,一些迭代器實現(xiàn)(包括 JRE 提供的所有通用 collection 實現(xiàn))可能選擇拋出此異常。執(zhí)行該操作的迭代器稱為快速失敗迭代器,因為迭代器很快就完全失敗,而不會冒著在將來某個時間任意發(fā)生不確定行為的風險。
注意,此異常不會始終指出對象已經由不同 線程并發(fā)修改。如果單線程發(fā)出違反對象協(xié)定的方法調用序列,則該對象可能拋出此異常。例如,如果線程使用快速失敗迭代器在 collection 上迭代時直接修改該 collection,則迭代器將拋出此異常。
注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證??焖偈〔僮鲿M最大努力拋出 ConcurrentModificationException。因此,為提高此類操作的正確性而編寫一個依賴于此異常的程序是錯誤的做法,正確做法是:ConcurrentModificationException 應該僅用于檢測 bug。
當使用 fail-fast iterator 對 Collection 或 Map 進行迭代操作過程中嘗試直接修改 Collection / Map 的內容時,即使是在單線程下運行, java.util.ConcurrentModificationException 異常也將被拋出。
Iterator 是工作在一個獨立的線程中,并且擁有一個 mutex 鎖。 Iterator 被創(chuàng)建之后會建立一個指向原來對象的單鏈索引表,當原來的對象數量發(fā)生變化時,這個索引表的內容不會同步改變,所以當索引指針往后移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。
所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前迭代對象的同時維護索引的一致性。
有意思的是如果你的 Collection / Map 對象實際只有一個元素的時候, ConcurrentModificationException 異常并不會被拋出。這也就是為什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
for(Person person : pList){
if(person.getGender()==Gender.MALE){
pList.remove(person); //不能在遍歷期間進行 remove這個操作
}
}
Map在遍歷時候通常 現(xiàn)獲得其鍵值的集合Set,然后用迭代器Iterator來對Map進行遍歷。
注意在遍歷的過程中,只能對Map中的元素進行相應的處理,不能把Map元素增加或者把Map元素減少,也就是說,不能改變Map的size大小,就會出現(xiàn)異常(不能在遍歷過程中修改刪除或者增加map中的元素)
報出的異常為 java.util.ConcurrentModificationException 異常
public class ConcurrentModificationExceptionextends RuntimeException
當方法檢測到對象的并發(fā)修改,但不允許這種修改時,拋出此異常。
例如,某個線程在 Collection 上進行迭代時,通常不允許另一個線性修改該 Collection。通常在這些情況下,迭代的結果是不明確的。如果檢測到這種行為,一些迭代器實現(xiàn)(包括 JRE 提供的所有通用 collection 實現(xiàn))可能選擇拋出此異常。執(zhí)行該操作的迭代器稱為快速失敗迭代器,因為迭代器很快就完全失敗,而不會冒著在將來某個時間任意發(fā)生不確定行為的風險。
注意,此異常不會始終指出對象已經由不同 線程并發(fā)修改。如果單線程發(fā)出違反對象協(xié)定的方法調用序列,則該對象可能拋出此異常。例如,如果線程使用快速失敗迭代器在 collection 上迭代時直接修改該 collection,則迭代器將拋出此異常。
注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證??焖偈〔僮鲿M最大努力拋出 ConcurrentModificationException。因此,為提高此類操作的正確性而編寫一個依賴于此異常的程序是錯誤的做法,正確做法是:ConcurrentModificationException 應該僅用于檢測 bug。
當使用 fail-fast iterator 對 Collection 或 Map 進行迭代操作過程中嘗試直接修改 Collection / Map 的內容時,即使是在單線程下運行, java.util.ConcurrentModificationException 異常也將被拋出。
Iterator 是工作在一個獨立的線程中,并且擁有一個 mutex 鎖。 Iterator 被創(chuàng)建之后會建立一個指向原來對象的單鏈索引表,當原來的對象數量發(fā)生變化時,這個索引表的內容不會同步改變,所以當索引指針往后移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。
所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前迭代對象的同時維護索引的一致性。
有意思的是如果你的 Collection / Map 對象實際只有一個元素的時候, ConcurrentModificationException 異常并不會被拋出。這也就是為什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
您可能感興趣的文章:
- Java遍歷集合報錯ConcurrentModificationException的原因分析與解決方法
- Java ConcurrentModificationException 深度剖析開發(fā)調試日志的解決方案
- Java?報錯?java.util.ConcurrentModificationException:?null?的原因及解決方案
- Java ConcurrentModificationException異常解決案例詳解
- 詳解Java刪除Map中元素java.util.ConcurrentModificationException”異常解決
- Java源碼解析ArrayList及ConcurrentModificationException
- 出現(xiàn)java.util.ConcurrentModificationException 問題及解決辦法
- java.util.ConcurrentModificationException 解決方法
- Java導致ConcurrentModificationException所有原因
相關文章
springboot啟動mongoDB報錯之禁用mongoDB自動配置問題
這篇文章主要介紹了springboot啟動mongoDB報錯之禁用mongoDB自動配置問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
Java讀取JSON文件并將其中元素轉為JSON對象輸出的方式
這篇文章主要介紹了Java讀取JSON文件并將其中元素轉為JSON對象輸出的方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-10-10
SpringBoot整合RabbitMQ的5種模式實戰(zhàn)
本文主要介紹了SpringBoot整合RabbitMQ的5種模式實戰(zhàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08
J2EE Servlet上傳文件到服務器并相應顯示功能的實現(xiàn)代碼
這篇文章主要介紹了J2EE Servlet上傳文件到服務器,并相應顯示,在文中上傳方式使用的是post不能使用get,具體實例代碼大家參考下本文2018-07-07

