问题
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at com.alpha.beta.purchasing.item.VendorItemList.loadItems(VendorItemList.java:51)
at com.alpha.beta.purchasing.Shipment.loadItems(Shipment.java:1006)
at com.alpha.beta.purchasing.Shipment.loadItems(Shipment.java:953)
at com.alpha.beta.purchasing.Shipment.getItemTotal(Shipment.java:1503)
at com.alpha.beta.purchasing.Shipment.getShipmentTotal(Shipment.java:854)
at com.alpha.beta.quickreports.PurchasingGenericListSourceMapper.fillPurchaseReceivingItemListForQuickReportsTask(PurchasingGenericListSourceMapper.java:144)
at com.alpha.beta.quickreports.PurchasingGenericListSourceMapper$2.run(PurchasingGenericListSourceMapper.java:105)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
I am getting above mentioned Exception and source code is below:
public void loadItems(ArrayList list) {
if(list != null && list.size() > 0) {
super.clear();
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
// VendorItem item = (VendorItem)iterator.next();
//load(new Integer(item.getVendorItemId()), item);
Object obj = iterator.next(); // << This is where it says exception comes
if(obj instanceof InvoiceItem) {
InvoiceItem item = (InvoiceItem)obj;
load(new Integer(item.getInvoiceItemId()), item);
//logger.debug("** loading invoice Item " + item.toString());
}
else if(obj instanceof PurchaseOrderItem) {
PurchaseOrderItem item = (PurchaseOrderItem)obj;
load(new Integer(item.getPoItemId()), item);
//logger.debug("** loading PO Item " + item.toString());
}
else if(obj instanceof ShipmentItem) {
ShipmentItem item = (ShipmentItem)obj;
load(new Integer(item.getShipmentItemId()), item);
logger.debug("** loading ShipmentItem Item " + item.toString());
}
//
else if(obj instanceof VendorItem) {
VendorItem item = (VendorItem)obj;
load(new Integer(item.getVendorItemId()), item);
logger.debug("** loading VendorItem " + item.toString());
}
//
else {
logger.debug("*** neither invoice/PO/shipment item");
}
}
}
}
I have seen the related questions but they doesn't meet my scenario so i was hoping that if someone can point out the real cause why this is happening.
回答1:
ArrayList is not synchronized. This means that in your TimerThread something else is modifying the ArrayList.
Here's what the docs say:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:
List list = Collections.synchronizedList(new ArrayList(...));
Wrapping this list using Collections.synchronizedList() should fix the problem.
回答2:
If load
is making changes to the ArrayList
while you're using an Iterator
, then yes, you're going to get a ConcurrentModificationException
as it leaves the iterator in an unknown state.
Lists have a second iterator (ListIterator, which can be fetched with .listIterator()) that can be used to make changes while iterating. Note that this only applies to changes made through the iterator... changes made outside the iterator are still going to have this issue.
CopyOnWriteArrayList is guaranteed to not throw ConcurrentModificationException
from its iterators, as it's thread-safe and changes make a new copy... but the iterator also won't be aware of any changes you've made.
来源:https://stackoverflow.com/questions/20199760/java-util-concurrentmodificationexception-in-arraylist-processing