How to deal with ConcurrentModificationException - java

I am getting the a ConcurrentModificationException from my cooldown timer. I use a thread to reduce the values every second like this:
public class CoolDownTimer implements Runnable {
#Override
public void run() {
for (String s : playerCooldowns.keySet()) {
playerCooldowns.put(s, playerCooldowns.get(s) - 20);
if (playerCooldowns.get(s) <= 0) {
playerCooldowns.remove(s);
}
}
}
}
So every second it should reduce every players cooldown by 20, but the problem is that I a getting the CME every couple hours while running the program, especially when lots of people are online. How do I make it so that if it is still modifying the list, it will wait until the current operation is done and create a sort of modification queue? Thanks! Here is the stack trace:
2012-06-18 20:59:05 [WARNING] Task of 'SurvivorsClasses' generated an exception
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:839)
at java.util.HashMap$KeyIterator.next(HashMap.java:874)
at me.zachoooo.survivorclasses.CoolDownManager$CoolDownTimer.run(CoolDownManager.java:13)
at org.bukkit.craftbukkit.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:126)
at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:533)
at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:459)
Line 13 is the start of the for loop...

You can't modify collections when using a foreach loop.
You can however iterate over the Map.entrySet() and do everything you need:
public void run() {
for (Iterator<Map.Entry<String,Integer>> i = playerCooldowns.entrySet().iterator(); i.hasNext();) {
Map.Entry<String,Integer> entry = i.next();
entry.setValue(entry.getValue() - 20); // update via the Map.Entry
if (entry.getValue() <= 0) {
i.remove(); // remove via the iterator
}
}
}

A ConcurrentModificationException is thrown while you try to modify the contents of your Collection, at the same time while Iterating through it.
Read this and this for more discussion on it.
The reason why sometimes it might work out for you is clearly mentioned in the documentation.
The iterators returned by all of this class's "collection view methods" are fail-fast: if
the map is structurally modified at any time after the iterator is created, in any way
except through the iterator's own remove method, the iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent modification, the
iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic
behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally
speaking, impossible to make any hard guarantees in the presence of unsynchronized
concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a
best-effort basis.

Unlike Array, Collections are Checked only during the Compilation time, NOT during the run time, thats the reason you cannot modify the Collection like put() or remove() in the loop.

Related

ConcurrentModificationException using Iterator

I'm using an iterator to loop over a collection as follows:
Iterator<Entity> entityItr = entityList.iterator();
while (entityItr.hasNext())
{
Entity curr = entityItr.next();
for (Component c : curr.getComponents())
{
if (c instanceof PlayerControlled)
{
((PlayerControlled) c).pollKeyboard();
}
}
}
However on the following line I get a ConcurrentModificationException
Entity curr = entityItr.next();
Why is this happening when I'm not altering anything?
Many thanks
Edit - stack trace:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at cw.systems.Input.checkInputs(Input.java:31)
at cw.systems.Input.begin(Input.java:21)
at cw.misc.Game.render(Game.java:73)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
You must be modifying the list either:
inside your iterator in the pollKeyboard method, without using the add or remove methods on the iterator; or
in another thread
Therefore your exception is the expected behaviour. From the docs, if you have a single thread iterating the list:
if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException
and if multiple threads uses the list at one time:
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
Solution:
If only one thread accesses the list, make sure you use the entityItr.remove or add methods to modify the list.
For the multi-threaded case you can use Collections.synchronizedList if you do not have a locking object available.
First store a single central reference to your list as:
entityList = Collections.synchronizedList(theOriginalArrayList);
And then access it (with all readers and writers) as:
synchronized (entityList) {
// Readers might do:
itr = entityList.iterator();
while (i.hasNext())
... do stuff ...
}
There are other ways to sync multi-threaded access, including copying the list to an array (inside a sync block) and iterating it for reading, or using a ReadWrite lock. They all depend on your exact requirement.
It looks that there is another thread using the same collection and modifing it when this code is iterating over the collection.
ConcurrentModificationException
You can use navite java concurrent collestions instead. They are thread safe. However it's a good habbit to create immutable collections - they are thread safe and enforce you to design reliable code.

Reason for ConcurrentModificationException on ArrayLists iterator.next()

I have no idea why a ConcurrentModificationException occurs when i iterate over an ArrayList. The ArrayList is methode scoped, so it should not be visible by other threads which execute the same code. At least if i understodd multi threading and variable scopes correctly.
Caused by: java.util.ConcurrentModificationException
at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64)
at com....StrategyHandler.applyStrategy(StrategyHandler.java:184)
private List<Order> applyStrategy(StorageObjectTree storageObjectTree) {
...
List<OrderHeader> finalList = new ArrayList<Order>();
for (StorageObject storageObject : storageObjectTree.getStorageObjects()) {
List<Order> currentOrders = strategy.process(storageObject);
...
if (currentOrders != null) {
Iterator<Order> iterator = currentOrders.iterator();
while (iterator.hasNext()) {
Order order = (Order) iterator.next(); // line 64
// read some values from order
}
finalList.addAll(currentOrders);
}
}
return finalList;
}
Can anybody give me an hint what could be the source of the problem?
If You have read the Java Doc for ConcurrentModifcationException :
It clearly states the condition in which it occurs:
This exception may be thrown by methods that have detected concurrent
modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it. In general,
the results of the iteration are undefined under these circumstances.
Some Iterator implementations (including those of all the general
purpose collection implementations provided by the JRE) may choose to
throw this exception if this behavior is detected. Iterators that do
this are known as fail-fast iterators, as they fail quickly and
cleanly, rather that risking arbitrary, non-deterministic behavior at
an undetermined time in the future.
Note that this exception does not always indicate that an object has
been concurrently modified by a different thread. If a single thread
issues a sequence of method invocations that violates the contract of
an object, the object may throw this exception. For example, if a
thread modifies a collection directly while it is iterating over the
collection with a fail-fast iterator, the iterator will throw this
exception.
Note that fail-fast behavior cannot be guaranteed as it is, generally
speaking, impossible to make any hard guarantees in the presence of
unsynchronized concurrent modification. Fail-fast operations throw
ConcurrentModificationException on a best-effort basis. Therefore, it
would be wrong to write a program that depended on this exception for
its correctness: ConcurrentModificationException should be used only
to detect bugs.
In your case as you said, you do not have multiple threads accessing this list. it might still be possible as per second paragraph above if your single thread that is reading from iterator might be trying to write to it as well.
Hope this helps.
This exception occurred when you changing/adding/removing values from your list and in the same time you are iterating it. And if you use many threads at the same time...
Try to surround your if by synchronized(currentOrders) { /* YOUR LAST CODE */ }.
I'm not sure of this but try it.
Depending on the implementation of strategy.process(..) it could be that this implementation has still a reference to the List it passed back as a result. If there are multiple Threads involved in this implementation it might be possible that the List is modified by one of these threads even after it is passed back as a result.
(If you know the "Future" pattern, you could perhaps imagine an implementation where a method immediately returns an empty List and adds the actual results later using another Thread)
You could try to create a new ArrayList "around" the result list and iterate over this copied list.
You might want to read this SO post. Basically switch and use CopyOnWriteArrayList if you can't see where the problem is coming from.

Java HashTable size() followed by values() safe in thread?

I have the following executing sequentially in the one thread:
int size = hashTable.size();
foreach.... in ... hasTable.values()
do something
My question will the foreach be executed size times ? (even if another thread puts/removes an element meanwhile ?
No, HashTable is thread-safe on method level (multiple threads can call any method at any time) but there is no cross-method synchronization. It's possible that between your two instructions other thread adds/removes or even clears the hashtable.
If you need to keep such invariant, make a defensive copy (doesn't have to be thread safe) and do size()/loop on that copy:
Map<K, V> map = null;
synchronized(hashTable) {
map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
//...
}
Here for-each is safe and it's guaranteed to run size-times. Also as noted in comments, you can just synchronize on hashTable:
synchronized(hashTable) {
int size = hashTable.size();
for(V v: hashTable.values()) {
//...
}
}
However this solution means that only one thread at a time can perform the loop (this can become a bottleneck if your loop takes some time to complete). With defensive copy each thread has its own copy and several threads can loop at the same time. On the other hand this solution is better if hashTable is very big (expensive to copy) but the iteration is very fast.
If another thread will modify the hashTable during the execution of the foreach than your code will throw a ConcurrentModificationException.
Your example is not thread safe, but it can be easily made thread safe like so:
synchronized(hashTable) {
int size = hashTable.size();
foreach.... in ... hasTable.values() {
// do something
}
}
Java HashTable size() followed by values() safe in thread?
So it's not values() method call that is unsafe. It's that you open an iterator on values() which is backed by the HashTable. It is the iterator which throws an exception if modifications are made to the table while it is iterating.
My question will the foreach be executed size times ? (even if another thread puts/removes an element meanwhile ?
As mentioned, the HashTable will throw an exception if it is modified while you are iterating across it.
HashTable has all but been deprecated. If you are looking for a modern, concurrent version of HashMap then you should be using ConcurrentHashMap which was added in Java 5. ConcurrentHashMap properly handles the case where modifications happen in the background as you iterate across it without extra synchronization or copying:
ConcurrentHashMap<...> map = new ConcurrentHashMap<...>();
int size = map.size();
for (... value : map.values()) {
// may be called more or less than size if other threads add or delete
...
}

altering collection over iteration

Modifying a set over iteration sometimes creates an exception, and other times it doesn't, why?
concurrent modification exception
Set<Integer> j = new HashSet<Integer>();
j.add(23);
j.add(45);
j.add(64);
int c=0;
for(Integer k: j)
{
if(c++==0)
{
j.remove(45);
}
}
System.out.println(j); // concurrent modification exception
<hr>
//works without exception
Set<Integer> j = new HashSet<Integer>();
j.add(23);
j.add(45);
j.add(64);
int c=0;
for(Integer k: j)
{
if(k==45)
{
j.remove(45);
}
}
System.out.println(j);//works without exception
From the JavaDocs for HashSet:
The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
(The highlighting is mine.)

java swing concurrency display text in JTextArea with a loop

I need to execute/display a series of events from a Arraylist to a JTextArea, however, each Event gets execute with different time. Following is the code, it fails while at second Event in the loop:
Thread worker = new Thread(new Runnable()
{
public void run()
{
while (eventList.size() > 0)
for (Event ev : eventList)
if(ev.ready())
{
/*try
{
Thread.sleep(1000);
} catch (InterruptedException e1)
{
e1.printStackTrace();
}*/
jTextArea.append(ev.toString() + "\n");
eventList.remove(ev);
}
}
});
worker.start();
I guess you got a ConcurrentModificationException. Try using an iterator, something like this:
Iterator<Event> it = eventList.iterator();
while(it.hasNext())
{
Event ev = it.next();
if (ev.ready())
it.remove();
}
Edit
Why did it throw a ConcurrentModificationException?
If you loop over a collection, using an Iterator directly or by using for(E : list), and you modify the collection, by calling add, remove or similar, you will get this exception. This tries to indicate there is a problem in the code. The problem is, one piece of code wants to loop over all the objects, while another piece of code adds or removes objects. The first piece of code gets in to trouble, how can it loop over everything if the collection keeps changing? So 'they' decided, you are not allowed to change a collection, when you loop over it. (Unless you change it with the iterator you use to loop, as this code does. it.remove(), it is the looping iterator and thus does not fail.) Hope that makes sense.
I may repeat what Lshtar said but I will add something of my own. Actually I took it from the book "J2EE Interview Companion".
The java.util Collection classes are fail-fast, which means that if one thread changes a collection while another thread is traversing it through with an iterator the iterator.hasNext() or iterator.next() call will throw ConcurrentModificationException. Even the synchronized collection wrapper classes SynchronizedMap and SynchronizedList are only conditionally thread-safe, which means all individual operations are thread-safe but compound
operations where flow of control depends on the results of previous operations may be subject to threading issues.
Solution:
Use ConcurrentHashMap or CopyOnWriteArrayList (java.util.concurrent package). Their iterators provide better scalability.

Categories