I am getting a concurrent modification exception on the following code:
for(Iterator<Tile> iter = spawner.activeTiles.iterator(); iter.hasNext();) {
Tile tile = iter.next();
canvas.drawRect(tile, tile.getColor());
}
I understand that concurrent modification happens when it is changed while it is iterating(adding/removing inside of the iteration). I also understand that they can happen when multithreading which is where I think my problem is.
In my game I have a few timers that run on threads. I have a spawner, which adds values to activeTiles on each tick. I then have a 2 timers, one for fading in and one for fading out. Without giving away my game, the tile is basically removed from the list when the fade out has finished, or when the player taps the tile. So there are a few instances where the tiles are removed from the list of tiles:
for(Iterator<Tile> iter = spawner.activeTiles.iterator(); iter.hasNext();) {
Tile tile = iter.next();
if(tile.contains(x, y) && tile.equals(spawner.activeTiles.get(0))) {
vibrator.vibrate(50);
tile.setBroken(true);
score ++;
spawner.setTileDelayInfo();
iter.remove();
and before each new spawn, it removes all of the failed tiles:
private void removeFailedTiles() {
for(Iterator<Tile> iter = activeTiles.iterator(); iter.hasNext();) {
Tile tile = iter.next();
if(tile.isFailed()) {
iter.remove();
}
}
}
It almost seems to happen randomly. So I think it has to do something with timing, but I am new to this kind of exception and don't really know what to look for or why this is happening.
The good news: you nailed the root cause of the problem in your question - you can't have multiple threads accessing a list at the same time unless they're all just reading.
You can address this in one of two ways, depending on how the rest of your code operates. The most 'correct' way is steffen's answer: any list access should be guarded with a synchronized block, and that includes holding the lock for the full duration of any list iterations. Note that if you do this, you want to do as little work as possible while holding the lock - in particular, it's a bad idea to do any sort of listener callbacks while holding a lock.
Your second option is to use a CopyOnWriteArrayList, which is thread-safe and doesn't require any external synchronization - but any modifications to the list (add/remove/replace calls) become significantly more expensive.
Multithreading can be a source of ConcurrentModificationExceptions. It can happen when one thread is modifying the structure of the collection while another thread has an Iterator iterating over it. This can lead to unexpected states in your application when the state of the collection changes when a section of code needs a consistent view of the data. This is needed when you're iterating over a collection of Tiles.
You need to syncrhonize access to the activeTiles collection. Anything that modifies this collection structurally (add or remove), or iterates over it, must synchronize on this collection.
Add a synchronized (activeTiles) block around all code that iterates or structuraly modifies activeTiles. This includes all 3 code snippets you've provided here.
Alternatively, you can make the 3 methods corresponding to your code snippets synchronized.
Either way, no other Thread can execute any of the synchronized blocks until another Thread is finished with its syncrhonized section, preventing the ConcurrentModificationException.
It's not safe to remove elements with an Iterator that supports element-removal, when you're iterating the collection in another thread.
Acquire a Lock in all threads on activeTiles before iterating them.
You might want to make your list thread-safe. Use Collections.synchronizedList().
threadSafeActiveTiles = Collections.synchronizedList(activeTiles);
Mind that you must synchronize on that list when iterating over it:
synchronized (threadSafeActiveTiles) {
for (Iterator<Tile> it = threadSafeActiveTiles.iterator(); it.hasNext();) {
Tile tile = it.next();
// ...
}
}
You then can safely have multiple threads modifying the list, which seems to be your case.
The list returned by Collections.synchronizedList() saves you from having to use the synchronized block (above) in single operations on that list, like add(e), size(), get(i) and so on...
Related
I am trying to find a good way to achieve the following API:
void add(Object o);
void processAndClear();
The class would store the objects and upon calling processAndClear would iterate through the currently stored ones, process them somehow, and then clear the store. This class should be thread safe.
the obvious approach is to use locking, but I wanted to be more "concurrent". This is the approach which I would use:
class Store{
private AtomicReference<CopyOnWriteArrayList<Object>> store = new AtomicReference<>(new CopyOnWriteArrayList <>());
void add(Object o){
store.get().add(o);
}
void processAndClear(){
CopyOnWriteArrayList<Object> objects = store.get();
store.compareAndSet(objects, new CopyOnWriteArrayList<>());
for (Object object : objects) {
//do sth
}
}
}
This would allow threads that try to add objects to proceed almost immediately without any locking/waiting for the xlearing to complete. Is this the more or less correct approach?
Your above code is not thread-safe. Imagine the following:
Thread A is put on hold at add() right after store.get()
Thread B is in processAndClear(), replaces the list, processes all elements of the old one, then returns.
Thread A resumes and adds a new item to the now obsolete list that will never be processed.
The probably easiest solution here would be to use a LinkedBlockingQueue, which would as well simplify the task a lot:
class Store{
final LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<>();
void add(final Object o){
queue.put(o); // blocks until there is free space in the optionally bounded queue
}
void processAndClear(){
Object element;
while ((element = queue.poll()) != null) { // does not block on empty list but returns null instead
doSomething(element);
}
}
}
Edit: How to do this with synchronized:
class Store{
final LinkedList<Object> queue = new LinkedList<>(); // has to be final for synchronized to work
void add(final Object o){
synchronized(queue) { // on the queue as this is the shared object in question
queue.add(o);
}
}
void processAndClear() {
final LinkedList<Object> elements = new LinkedList<>(); // temporary local list
synchronized(queue) { // here as well, as every access needs to be properly synchronized
elements.addAll(queue);
queue.clear();
}
for (Object e : elements) {
doSomething(e); // this is thread-safe as only this thread can access these now local elements
}
}
}
Why this is not a good idea
Although this is thread-safe, it is much slower if compared to the concurrent version. Assume that you have a system with 100 threads that frequently call add, while one thread calls processAndClear. Then the following performance bottle-necks will occur:
If one thread calls add the other 99 are put on hold in the meantime.
During the first part of processAndClear all 100 threads are put on hold.
If you assume that those 100 adding threads have nothing else to do, you can easily show, that the application runs at the same speed as a single-threaded application minus the cost for synchronization. That means: adding will effectively be slower with 100 threads than with 1. This is not the case if you use a concurrent list as in the first example.
There will however be a minor performance gain with the processing thread, as doSomething can be run on the old elements while new ones are added. But again the concurrent example could be faster, as you could have multiple threads do the processing simultaneously.
Effectively synchronized can be used as well, but you will automatically introduce performance bottle-necks, potentially causing the application to run slower as single-threaded, forcing you to do complicated performance tests. In addition extending the functionality always contains a risk of introducing threading issues, as locking needs to be done manually.A concurrent list in contrast solves all these problems without additional code and the code can easily changed or extended later on.
The class would store the objects and upon calling processAndClear would iterate through the currently stored ones, process them somehow, and then clear the store.
This seems like you should use a BlockingQueue for this task. Your add(...) method would add to the queue and your consumer would call take() which blocks waiting for the next item. The BlockingQueue (ArrayBlockingQueue is a typical implementation) takes care of all of the synchronization and signaling for you.
This means that you don't have to have a CopyOnWriteArrayList nor an AtomicReference. What you would lose is a collection and you can iterate through for other reasons than your post articulates currently.
I want to create a static arrayList for communication between 3 threads:
1. thread will add some data to list;
2. thread will remove data from list;
3. thread (timer every 3 sec) will check if size of list equals 0, and if no print all object of this list.
I'm wondereing what would happen if more than 1 thread will try to access this list at same time (for example timer will check size of list at same time when second thread will be removeing object from list).
I guess that i have to synchronize this list, but have no idea how to do that. Can you give me some advise?
I'm wondereing what would happen if more than 1 thread will try to
access this list at same time
Firstly ArrayList is not thread-safe, so you should not use it directly.
One possibility is to use Collections.synchronizedList(...); which provides you thread safety but will hamper concurrency.
Your requirement seems to be like a Queue, so you should use BlockingQueue for that, e.g LinkedBlockingQueue which is thread-safe.
NOTE:
Compound operations on list will still be unsafe if you use Collections.synchronizedList(...).
You can use
List myList = Collections.synchronizedList(new ArrayList());
ArrayList is not thread-safe. You will need to handle the synchronization by yourself or the results will be unpredictable.
As suggested in the related question: How do I make my arraylist thread safe you could use Collections.synchronizedList(...) to obtain a thread-safe version of your List
The javadoc gives an example of how to utilize the List returned by that method.
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Other solutions have already suggested this, but using this approach has a potential performance penalty since the synchronization blocks concurrent access to the List. This will ultimately limit the rate at which you are able to add & remove data from the backing List.
This code snippet will help you in the right direction
//have a lock Object
private static final Object lock = new Object();
// your list
private static List list = null
//synchronized on lock object. this will allow only one thread at a time
synchronized(lock){
//access,add to, remove from list
}
By this way, you can make sure there is only one thread at a time accessing your list
Better yet, using concurrency primitives (wait, notify, and synchronized) you can have the printing thread wait, and only wake up after one of the other threads actually changed the ArrayList. This has the advantage of not printing when there's no change, and being woken up immediately when a change happens. You may still get false wake-ups, but can be coded around if it's a problem.
In printing thread:
synchronized(lock)
{
while(true/*or some boolean to indicate you're done*/)
{
lock.wait();
//print list
}
}
In a thread that edits the list:
synchronized(lock)
{
//modify list
lock.notify();
}
You can also do lock.wait(3000); to print after 3 seconds anyway even if no change happens.
Please, help me understand the error I am getting:
private void replayHistory() {
synchronized (alarmsHistory) {
for (AlarmEvent alarmEvent : alarmsHistory) {
LOG.error("replayHistory " + alarmEvent.type + " " + alarmEvent.source);
sendNotification(alarmEvent.type, alarmEvent.source, alarmEvent.description,
alarmEvent.clearOnOtherStations, alarmEvent.forceClearOnOtherStations);
}
}
}
and the method that adds an element to it
private void addToAlarmsHistory(AlarmEvent alarmEvent) {
synchronized (alarmsHistory) {
LOG.error("addToAlarmsHistory " + alarmEvent.type + " " + alarmEvent.source);
alarmsHistory.add(alarmEvent);
}
}
both methods and the Set
private volatile Set<AlarmEvent> alarmsHistory = new LinkedHashSet<AlarmEvent>();
are defined in
JmxGwReloadThread extends Thread class
which is an inner class in
AlarmManager class
that has a method
private void addToReplayHistory(AlarmEvent alarmEvent) {
if ((jmxThread != null) && (jmxThread.isAlive())) {
jmxThread.addToAlarmsHistory(alarmEvent);
}
}
which is being called by different interfaces (cannot assure when and how often)
At some point JmxThread is started and calls replayHistory method
java.util.ConcurrentModificationException is thrown, the root is from the
for (AlarmEvent alarmEvent : alarmsHistory) {
The code propably tries to add an element to the alarmsHistory and when interator
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:390)
at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:401)
at AlarmManager$JmxGwReloadThread.replayHistory(AlarmManager.java:568)
at AlarmManager$JmxGwReloadThread.run(AlarmManager.java:532)
throws exception upon calling nextEntry, but should't synchronization prevent from such an issue?
Logs show that synchronization does not work - replayHistory should iterate over all its elements (I can asure its more then one single HEARTBEAT_INFO FM) but it's interrupted by the addToReplayHistory call.
2013-07-11 11:58:33,951 Thread-280 ERROR AlarmManager$JmxGwReloadThread.replayHistory(AlarmManager.java:570) - replayHistory HEARTBEAT_INFO FM
2013-07-11 11:58:33,951 Thread-280 ERROR AlarmManager$JmxGwReloadThread.addToAlarmsHistory(AlarmManager.java:550) - addToAlarmsHistory HEARTBEAT_INFO FM
2013-07-11 11:58:33,952 Thread-280 ERROR Log4jConfigurator$UncaughtExceptionHandler.uncaughtException(Log4jConfigurator.java:253) - Detected uncaught exception in thread: Thread-280
One thing OP (and probably most people) should be aware of:
ConcurrentModificationException has nothing to do with multi-threading.
Although multi-threading makes it much easier to happen, but the core of this problem has nothing to do with multi-threading.
This is mostly caused by scenario like,
Get the iterator from a collection,
Before finish using that iterator, the collection is structurally modified.
Keep on using the iterator after 2. The iterator will detect the collection is structurally modified and will throw out ConcurrentModificationException.
Of course, not all collection have such behavior, e.g. ConcurrentHashMap. Definition of "Structurally Modified" is different for different collection too.
That means, even I have only 1 thread, if I do something like:
List<String> strings = new ArrayList<String>();
//....
for (String s: strings) { // iterating through the collection
strings.add("x"); // structurally modifying the collection
}
I will get ConcurrentModificationException even it is all happening in single thread.
There are different ways to solve the problem, depending on your requirement or problem. e.g.
If it is simply due to multi-thread access, proper synchronize access can be one solution
You may make use of Collection that iterator is safe from structural modification (e.g. ConcurrentHashMap)
Adjust your logic to either re-acquire the iterator again if you modified the collection, or makes your modification using the iterator (some collection impls allows that), or make sure modification to collection happens after you finish using the iterator.
Given that your code seems having proper synchronization on alarmHistory, there are two directions you would want to check
Is there any possible modification of alarmHistory inside sendNotification()? For example, adding or removing from alarmHistory?
Is there other possible unsynchronized access to alarmHistory which may modify the structure?
If one thread iterates, and another thread adds, you're hosed.
Given that your code seems to synchronise access to the two relevant blocks of code, look for other unsynchronized code that adds/removes from alarmsHistory.
The only idea which comes to my head that you have an intricate logic behind the scene. I think the sendNotification somehow recursively invokes addToReplayHistory. So, the multithreading is a red herring, the log file shows only one thread involved, and immideately after sendNotification there is addToReplayHistory call which modifies the collection and breaks the interator.
More info is in the javadoc for the exception:
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.
To add some details to kan's answer:
The synchronized block in Java is reentrant:
Reentrant SynchronizationRecall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.
So like kan pointed out, it might in fact be that not multiple threads are modifying your collection but only one thread which, due to the reentrant behavior, may always acquire the lock.
The things you should look for to fix the exception are recursive calls between synchronized blocks, or unsychronized access to alarmsHistory.
You can also look into concurrent collections like ConcurrentSkipList or CopyOnWriteArraySet. Both should prevent the exception, but beware of their behavior and performance characteristics described in the JavaDoc.
I have a singleton logger that contains a vector. Objects from outside can append information to this vector by calling singletonLogger.append(String data) and read the whole vector by calling singletonLogger.getLogEntries() which returns a string.
It would be nice to overload the getLogEntries-method with an int-parameter, e.g. getLogEntries(int x), to be able to get only the last x entries instead of the whole log.
Without regarding mutliple threads, this would be easy, something like:
String getLogEntries(int x) {
int size = vector.size();
for(int i = size; i > (size - x); i--) {
// StringBuilder.append(vector.elementAt....
}
}
But of course, this is not really safe when taking multiple threads into account. Imagine the vector gets cleared by another method shortly after its size was determined by the method above, the loop will crash.
On the other hand, I do not want to mark the whole method as synchronized, because the loop processing could last 5 - 10 seconds. This would block all the code that is trying to call the logger's methods, right?
Is there another way to reliably get the last x elements of a vector?
Thanks
Edit
Vector has a sublist method that should work and be synchronized but that doesn't solve someone clearing the Vector in another thread. You could use ReadWriteLock and get a readLock() when reading from the end of the Vector using sublist() and a writeLock() (which guarantees exclusive access) when clear() needs to be called. If your background thread is writing the log entries to disk or something, it should count the number of line written, and then get a writeLock() and remove those from the front of the list instead of calling clear(). That would limit the time under the lock to be more efficient.
You might also consider maintaining your own internal queue so you can control the synchronization specifically. This may make it easier to clear the earlier entries from the queue. Then again you may need a ReadWriteLock for that as well.
Did you consider copying the relevant elements to a new Vector in a synchronized block and then handling them outside one?
Currently in a multithreaded environment, we are using a LinkedList to hold data. Sometimes in the logs we get NoSuchElementException while it is polling the linkedlist. Please help in understanding the performance impact if we move from the linkedlist to ConcurrentLinkedQueue implementation.
Thanks,
Sachin
When you get a NoSuchElementException then this maybe because of not synchronizing properly.
For example: You're checking with it.hasNext() if an element is in the list and afterwards trying to fetch it with it.next(). This may fail when the element has been removed in between and that can also happen when you use synchronized versions of Collection API.
So your problem cannot really be solved with moving to ConcurrentLinkedQueue. You may not getting an exception but you've to be prepared that null is returned even when you checked before that it is not empty. (This is still the same error but implementation differs.) This is true as long as there is no proper synchronization in YOUR code having checks for emptiness and element retrieving in the SAME synchronized scope.
There is a good chance that you trade NoSuchElementException for having new NullPointerException afterwards.
This may not be an answer directly addressing your question about performance, but having NoSuchElementException in LinkedList as a reason to move to ConcurrentLinkedQueue sounds a bit strange.
Edit
Some pseudo-code for broken implementations:
//list is a LinkedList
if(!list.isEmpty()) {
... list.getFirst()
}
Some pseudo-code for proper sync:
//list is a LinkedList
synchronized(list) {
if(!list.isEmpty()) {
... list.getFirst()
}
}
Some code for "broken" sync (does not work as intended).
This maybe the result of directly switching from LinkedList to CLQ in the hope of getting rid of synchronization on your own.
//queue is instance of CLQ
if(!queue.isEmpty()) { // Does not really make sense, because ...
... queue.poll() //May return null! Good chance for NPE here!
}
Some proper code:
//queue is instance of CLQ
element = queue.poll();
if(element != null) {
...
}
or
//queue is instance of CLQ
synchronized(queue) {
if(!queue.isEmpty()) {
... queue.poll() //is not null
}
}
ConcurrentLinkedQueue [is] an unbounded, thread-safe, FIFO-ordered queue. It uses a linked structure, similar to those we saw in Section 13.2.2 as the basis for skip lists, and in Section 13.1.1 for hash table overflow chaining. We noticed there that one of the main attractions of linked structures is that the insertion and removal operations implemented by pointer rearrangements perform in constant time. This makes them especially useful as queue implementations, where these operations are always required on cells at the ends of the structure, that is, cells that do not need to be located using the slow sequential search of linked structures.
ConcurrentLinkedQueue uses a CAS-based wait-free algorithm that is, one that guarantees that any thread can always complete its current operation, regardless of the state of other threads accessing the queue. It executes queue insertion and removal operations in constant time, but requires linear time to execute size. This is because the algorithm, which relies on co-operation between threads for insertion and removal, does not keep track of the queue size and has to iterate over the queue to calculate it when it is required.
From Java Generics and Collections, ch. 14.2.
Note that ConcurrentLinkedQueue does not implement the List interface, so it suffices as a replacement for LinkedList only if the latter was used purely as a queue. In this case, ConcurrentLinkedQueue is obviously a better choice. There should be no big performance issue unless its size is frequently queried. But as a disclaimer, you can only be sure about performance if you measure it within your own concrete environment and program.