Why does this code throw a java ConcurrentModificationException? - java

public final class ClientGateway {
private static ClientGateway instance;
private static List<NetworkClientListener> listeners = Collections.synchronizedList(new ArrayList<NetworkClientListener>());
private static final Object listenersMutex = new Object();
protected EventHandler eventHandler;
private ClientGateway() {
eventHandler = new EventHandler();
}
public static synchronized ClientGateway getInstance() {
if (instance == null)
instance = new ClientGateway();
return instance;
}
public void addNetworkListener(NetworkClientListener listener) {
synchronized (listenersMutex) {
listeners.add(listener);
}
}
class EventHandler {
public void onLogin(final boolean isAdviceGiver) {
new Thread() {
public void run() {
synchronized (listenersMutex) {
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
}
}
}.start();
}
}
}
This code throws a ConcurrentModificationException
But I thought if they are both synchronized on the listenersMutex then they should be executed in serial? All code within functions that operate on the listeners list operate within syncrhonized blocks that are synchronized on the Mutex. The only code that modifies the list are addNetworkListener(...) and removeNetworkListener(...) but removeNetworkListener is never called at the moment.
What appears to be happening with the error is that a NetworkClientListener is still being added while the onLogin function/thread is iterating the listeners.
Thank you for your insight!
EDIT: NetworkClientListener is an interface and leaves the implementation of "onLogin" up to the coder implementing the function, but their implementation of the function does not have access to the listeners List.
Also, I just completely rechecked and there is no modification of the list outside of the addNetworkListener() and removeNetworkListener() functions, the other functions only iterate the list. Changing the code from:
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
To:
for(int i = 0; i < listeners.size(); i++)
nl.onLogin(isAdviceGiver);
Appears to solve the concurrency issue, but I already knew this and would like to know what's causing it in the first place.
Thanks again for your continuing help!
Exception:
Exception in thread "Thread-5" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:782)
at java.util.ArrayList$Itr.next(ArrayList.java:754)
at chapchat.client.networkcommunication.ClientGateway$EventHandler$5.run(ClientGateway.java:283)
EDIT Okay, I feel a little dumb. But thank you for all your help! Particularly MJB & jprete!
Answer: Someone's implementation of onLogin() added a new listener to the gateway. Therefore(since java's synchronization is based on Threads and is reentrant, so that a Thread may not lock on itself) when onLogin() was called we in his implementation, we were iterating through the listeners and in the middle of doing so, adding a new listener.
Solution: MJB's suggestion to use CopyOnWriteArrayList instead of synchronized lists

Mutexes only guard from access from multiple threads. If nl.onLogin() happens to have logic that adds a listener to the listeners list, then a ConcurrentModificationException may be thrown, because it's being accessed (by the iterator) and changed (by the add) simultaneously.
EDIT: Some more information would probably help. As I recall, Java collections check for concurrent modifications by keeping a modification count for each collection. Every time you do an operation that changes the collection, the count gets incremented. In order to check the integrity of operations, the count is checked at the beginning and end of the operation; if the count changed, then the collection throws a ConcurrentModificationException at the point of access, not at the point of modification. For iterators, it checks the counter after every call to next(), so on the next iteration of the loop through listeners, you should see the exception.

I must admit that I don't see it either - if indeed removeListeners is not called.
What is the logic of the nl.onLogin bit? If it modified stuff, it could cause the exception.
A tip btw if you expect listeners to be moderately rare in being added, you could make the list CopyOnWriteArrayList type -- in which case you don't need your mutexes at all - CopyOnWriteArrayList is totally thread safe, and returns a weakly consistent iterator that will never throw CME (except where I just said, in nl.onLogin).

Instead of ArrayList , use can use thread-safe class CopyOnWriteArrayList which does not throw ConcurrentModificationException even if it is modified while iterating. While iterating if it is attempted to modify(add,update) then it makes a copy of the list, but iterater will continue working on original one.
Its a bit slower than ArrayList . It is useful in cases where you do not want to syncronise the iterations.

Related

Understanding synchronized on listeners notifiers

I have singleton thread class that sometimes calls function below and notifies listeners from it's thread run() method :
public class Serial implements Runnable
{
private ArrayList observers = new ArrayList();
...
public void run()
{
notifyListeners(new CS());
}
public synchronized void notifyListeners(CS value)
{
log.debug("notifying listeners with Control ");
int os = observers.size();
for (int i = 0; i < observers.size(); i++)
{
MListener observer = (MListener) observers.get(i);
observer.dataReceived(value);
}
}
...
public void addListener(MListener lsn)
{
observers.add(lsn);
}
public void removeListener(MListener lsn)
{
observers.remove(lsn);
}
}
I'm just wondering what gives synchronized on notifyListeners method? One of reasons - not allow add/remove observers from/to ArrayList observers while notifyListeners is called. Please correct me if I'm wrong. What more it might give?
UPD
I have updated my code with two methods addListener and removeListener. I suppose it is mistake since both of these methods are not synchronized and might be called from another thread ?
IMO the synchronization on notify does not make sense. If I understand you correctly, the notify method is only called by your singleton thread.
But your observer implementations content probably might be accessed by different threads. There the access to internal state must be synchronized.
E.g. if you want to save the given value to a member of the observer, which later is used by e.g. the main GUI thread you must synchronize the access to this member:
// called by your notify thread
void dataReceived( CS value)
{
synchronized (this)
{
myValue = value;
}
}
and:
// called by your GUI main thread:
public CS getValue()
{
synchronized (this)
{
// optional check for not null:
if ( myValue == null) throw new IllegalStateException();
logger.debug( "returning value: " + myValue);
return myValue;
}
}
If the CS is an AtomicXY (e.g. AtomicInteger) class, the synchronization is not needed. But if you want to do more than just assigning/returning the value (e.g. some checking or log output) the synchronization is mandatory.
The answer mostly depends on your context because it could be for 2 potential reasons:
We want to protect your list of listeners from concurrent accesses and modifications because it is an ArrayList which is not thread-safe (assuming that that the list can be modified elsewhere in your code and any time it is modified it is protected by a synchronized block with this as object's monitor otherwise it would not be done properly and/or it would be useless).
We want to prevent concurrent notifications for some internal logic.
In your case as you only have one thread that calls notifyListeners #2 should not be the reason unless the code owner assumed that you could have several threads doing this task in the future.
The reason #1 makes sense only if the list of observers can be modified by other threads concurrently if it is not possible you can simply remove the keyword synchronized from your method declaration as it would be useless so it would affect the performances for nothing.
Assuming that #1 is the reason, you should rather use the thread-safe List CopyOnWriteArrayList instead of an ArrayList because it is very efficient in mostly read accesses scenarios which is generally the case of a list of observers that we mostly read and rarely modify, your code would then be something like that:
public class Serial implements Runnable {
private final List<MListener> observers = new CopyOnWriteArrayList<>();
...
public void notifyListeners(CS value) {
log.debug("notifying listeners with Control ");
for (MListener observer : observers) {
observer.dataReceived(value);
}
}
I suppose it is mistake since both of these methods are not
synchronized and might be called from another thread ?
I confirm that the current code is not correct since your list of observers can be modified by concurrent threads thanks to the public methods addListener and removeListener and those methods don't modify your list within a synchronized block with this as object's monitor such that the current code is not thread-safe as it doesn't prevent concurrent accesses to your non thread-safe list.

How can a synchronized iteration on a Set fail with a ConcurrentModificationException [duplicate]

This question already has answers here:
ConcurrentModificationException (Java)
(3 answers)
Closed 9 years ago.
I have a class which stores data and gets called from many threads. It fails with a ConcurrentModificationException although every access to my Set is synchronized.
How can this happen? The synchronized should make sure that my Set is not changed while it is iterated...
Here are all functions from my class that access the Set...
Can anyone tell me what is going wrong here?
private final Object mListenerLock = new Object();
private final Set<IRetainerBaseListener> mListeners = new HashSet<IRetainerBaseListener>();
protected final void register(IRetainerBaseListener listener)
{
synchronized (mListenerLock)
{
mListeners.add(listener);
}
}
protected final boolean unregister(IRetainerBaseListener listener)
{
synchronized (mListenerLock)
{
return mListeners.remove(listener);
}
}
private final void onObjectAdded(RKey key, Object data)
{
synchronized (mListenerLock)
{
Iterator<IRetainerBaseListener> it = mListeners.iterator();
while (it.hasNext())
{
IRetainerBaseListener listener = it.next();
/* EDIT */
/* I'm not changing the Set in here, never!!! */
// I can't insert the if's, but I just check the interface class
// and call one of the following methods:
((IRetainerListener) listener).onRetainerDataAdded(key, data);
// or
((IRetainerSingleKeyListener) listener).onRetainerDataAdded(data);
}
}
}
It's not a problem of thread safety.
You are removing items while iterating on your collection. This is only possible using an iterator.
/*
* *it* does not appreciate that you removed elements
* in another way than it.remove();
* The iterator must do the add/remove operations itself
* to guarantee that it will not break the iteration.
*/
while (it.hasNext()) {
IRetainerBaseListener listener = it.next();
...
}
Synchronized is ensuring that no other thread is executing while also trying to hold a 'lock' during that operations.
Example:
Thread A:
synchronized(mListenerLock) {
doSomething;
}
Thread B:
synchronized(mListenerLock) {
doSomething;
}
This way either A or B is doing something. One have to wait for the other to release the binary 'lock' of mListenerLock.
In your case you use the very same thread to perform your actions. So you get the concurrent modification exception because you alter the state of the list (removing objects) while also iterating it.
ConcurrentModificationException does not refer to a concurrency problem in terms of threads. It is just stating that while doing one thing with a list (or related objects) your program does some other things that prevents things from working as intended. It is a (defensive) safety mechanism to prevent common bugs to happen unnoticed.

java.util.ConcurrentModificationException: Unexpected List modification while multithreading?

I'm using multithreading to process a List of Strings in batches, however I'm getting this error when the Runnable task is iterating over the List to process each String.
For example the code roughly follows this structure:
public class RunnableTask implements Runnable {
private List<String> batch;
RunnableTask(List<String> batch){
this.batch = batch;
}
#Override
public void run() {
for(String record : batch){
entry = record.split(",");
m = regex.matcher(entry[7]);
if (m.find() && m.group(3) != null){
currentKey = m.group(3).trim();
currentValue = Integer.parseInt(entry[4]);
if ( resultMap.get(currentKey) == null ){
resultMap.put(currentKey, currentValue);
} else {
resultMap.put(currentKey, resultMap.get(currentKey) + currentValue);
}
}
}
}
}
Where the thread that is passing these batches for processing never modifies "batch" and NO CHANGES to batch are made inside the for loop. I understand that this exception ConcurrentModificationException is due to modifying the List during iteration but as far as I can tell that isn't happening. Is there something I'm missing?
Any help is appreciated,
Thankyou!
UPDATE1: It seems instance-variables aren't thread safe. I attempted to use CopyOnWriteArrayList in place of the ArrayList but I received inconsistent results - suggesting that the full iteration doesn't complete before the list is modified in some way and not every element is being processed.
UPDATE2: Locking on the loop with sychronized and/or a reentrantlock both still give the same exception.
I need a way to pass Lists to Runnable tasks and iterate over those lists without new threads causing concurrency issues with that list.
I understand that this exception ConcurrentModificationException is due to modifying the List during iteration but as far as I can tell that isn't happening
Ok, consider what happens when you create a new thread, passing a reference to RunnableTask instance, initialized with a different list as constructor parameter? You just changed the list reference to point to different list. And consider what happens when at the same time, a different thread inside the run() method, is changing the list, at any point. This will at some point of time, throw ConcurrentModificationException.
Instance Variables are not Thread-Safe.
Try this in your code:
public void run() {
for(String record : new ArrayList(batch)){
//do processing with record
}
}
There is a sort of problem with all your threads processing the list (is the list modified during the process?) but is difficult to tell with the code you're providing
Problem is due to multiple thread concurrently modifying the the source List structure. What I would suggest you should devide the source list to new sublist(according to size) and pass that list to threads.
Say your source List have 100 elements. and you are running 5 concurrent thread.
int index = 0;
List<TObject> tempList = new ArrayList<>();
for(TObject obj:srcList){
if(i==(srcList.size()/numberOfthread)){
RunnableTask task = new RunnableTask(tempList);
tempList = new ArrayList<>();
}else
tempList.add(obj);
}
In this case your original list would not be modified.
you need to lock the list before accessing its elements. because List is not thread safe. Try this
public void run() {
synchronizd(batch){
for(String record : batch){//do processing with record}
}
}
yes you are getting ConcurrentModificationException because your List is getting modified during iteration. If performance is not a critical issue I suggest use synchronization.
public class RunnableTask implements Runnable {
private List<String> batch = new ArrayList<String>();
RunnableTask(List<String> batch){
this.batch = batch;
}
public void run() {
synchronized (batch) {
for(String record : batch){//do processing with record}
}
}
}
}
or even better use ReentrantLock.
Your followups indicate that you are trying to reuse the same List multiple times. Your caller must create a new List for each Runnable.
Obviously someone else is changing the content of the list, which is out of picture of the code you mentioned. (If you are sure that the ConcurrentModificationException is complaining for the batch list, but not resultMap, and you are actually showing all code in RunnableTask)
Try to search in your code, for places that is updating the content of the list, check if it is possible concurrently with your RunnableTask.
Simply synchronizing in the RunnableTask is not going to help, you need to synchronize all access to the list, which is obviously happening somewhere else.
If performance is an issue to you so that you cannot synchronize on the batch list (which prohibit multiple RunnableTask to execute concurrently), consider making use of ReaderWriterLock: RunnableTask acquires read lock, while the list update logic acquire the write lock.

List ConcurrentModificationException in servlet

It's plenty of questions regarding ConcurrentModificationException for ArrayList objects, but I could not find yet an answer to my problem.
In my servlet I have an ArrayList as a member object:
List myList<Object> = new ArrayList<Object> (...);
The list must be shared among users and sessions.
In one of the servlet's methods, method1, I need to iterate over the ArrayList items, and eventually add clear the list after the iteration. Here a snippet:
for (Object o : myList) {
// read item o
}
myList.clear();
In another method, method2, I simply add a new Item to the list.
Most of the times the method ends its job without errors. Sometimes, probably due to the concurrent invocation of this method by different users, I get the famous java util.ConcurrentModificationException exception.
Should I define my List as:
List myList = Collections.synchronizedList(new ArrayList(...));
Would this be enough or am I missing something? What's behind the scenes? When there is a possible concurrency, is the second thread held in standby by the container?
EDIT: I have added the answers to some comments.
Using a synchronized list will not solve your problem. The core of the problem is that you are iterating over a list and modifying it at the same time. You need to use mutual exclusion mechanisms (synchronized blocks, locks etc) to ensure that they do not happen at the same time. To elaborate, if you start with:
methodA() {
iterate over list {
}
edit list;
}
methodB() {
edit list;
}
If you use a synchronized list, what you essentially get is:
methodA() {
iterate over list {
}
synchronized {
edit list;
}
}
methodB() {
synchronized {
edit list;
}
}
but what you actually want is:
methodA() {
synchronized {
iterate over list {
}
edit list;
}
}
methodB() {
synchronized {
edit list;
}
}
Just using synchronizedList makes all methods thread safe EXCEPT Iterators.
I would use CopyOnWriteArrayList. It is thread safe and doesn't produce ConcurrentModificationException.
ConcurrentModificaitonException occurs when you attempt to modify a collection while you're iterating through it. I imagine that the error only gets thrown when you perform some conditional operation.
I'd suggest pushing the values you want to add/remove into a separate list and performing the add /remove after you're done iterating.
You need to lock not just over the method accesses but over your use of the list.
So if you allocate a paired Object like:
Object myList_LOCK = new Object();
then you can lock that object whenever you are accessing the List, like this:
synchronized(myList_LOCK) {
//Iterate through list AND modify all within the same lock
}
at the moment the only locking you're doing is within the individual methods of the List, which isn't enough in your case because you need atomicity over the entire sequence of iteration and modification.
You could use the actual object (myList) to lock rather than a paired object but in my experience you are better off using another dedicated object as it avoids unexpected deadlock conditions that can arise as a result of the code internal to the object locking on the object itself.
This is kind of an add onto Peter Lawery's answer. But since copying wouldn't effect you too negatively you can do a mixture of copying with synchronization.
private final List<Object> myList = new ArrayList<Object>();
public void iterateAndClear(){
List<Object> local = null;
synchronized(myList){
local = new ArrayList<Object>(myList);
myList.clear();
}
for(Object o : local){
//read o
}
}
public void add(Object o){
synchronized(myList){
myList.add(o);
}
}
Here you can iterate over o elements without fear of comodifications (and outside of any type of synchronization), all while myList is safely cleared and added to.

How to correctly create a SynchronizedStack class?

I made a simple synchronized Stack object in Java, just for training purposes.
Here is what I did:
public class SynchronizedStack {
private ArrayDeque<Integer> stack;
public SynchronizedStack(){
this.stack = new ArrayDeque<Integer>();
}
public synchronized Integer pop(){
return this.stack.pop();
}
public synchronized int forcePop(){
while(isEmpty()){
System.out.println(" Stack is empty");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return this.stack.pop();
}
public synchronized void push(int i){
this.stack.push(i);
notifyAll();
}
public boolean isEmpty(){
return this.stack.isEmpty();
}
public synchronized void pushAll(int[] d){
for(int i = 0; i < d.length; i++){
this.stack.push(i);
}
notifyAll();
}
public synchronized String toString(){
String s = "[";
Iterator<Integer> it = this.stack.iterator();
while(it.hasNext()){
s += it.next() + ", ";
}
s += "]";
return s;
}
}
Here are my questions:
Is it OK not to synchronize the isEmtpy() method? I figured it was because even if another Thread is modifying the stack at the same time, it would still return a coherent result (there is no operation that goes into a isEmpty state that is neither initial or final). Or is it a better design to have all the methods of a synchronized object synchronized?
I don't like the forcePop() method. I just wanted to create a thread that was able to wait until an item was pushed into the stack before poping an element, and I thought the best option was to do the loop with the wait() in the run() method of the thread, but I can't because it throws an IllegalMonitorStatException. What is the proper method to do something like this?
Any other comment/suggestion?
Thank you!
Stack itself is already synchronized, so it doesn't make sense to apply synchronization again (use ArrayDeque if you want a non-synchronized stack implementation)
It's NOT OK (aside from the fact from the previous point), because lack of synchronization may cause memory visibility effects.
forcePop() is pretty good. Though it should pass InterruptedException without catching it to follow the contract of interruptable blocking method. It would allow you to interrupt a thread blocked at forcePop() call by calling Thread.interrupt().
Assuming that stack.isEmpty() won't need synchronization might be true, but you are relying on an implementation detail of a class that you have no control over.
The javadocs of Stack state that the class is not thread-safe, so you should synchronize all access.
I think you're mixing idioms a little. You are backing your SynchronizedStack with java.util.Stack, which in turn is backed by java.util.Vector, which is synchronized. I think you should encapsulate the wait() and notify() behaivor in another class.
The only problem with not synchronizing isEmpty() is that you don't know what's happening underneath. While your reasoning is, well, reasonable, it assumes that the underlying Stack is also behaving in a reasonable manner. Which it probably is in this case, but you can't rely on it in general.
And the second part of your question, there's nothing wrong with a blocking pop operation, see this for a complete implementation of all the possible strategies.
And one other suggestion: if you're creating a class that is likely to be re-used in several parts of an application (or even several applications), don't use synchronized methods. Do this instead:
public class Whatever {
private Object lock = new Object();
public void doSomething() {
synchronized( lock ) {
...
}
}
}
The reason for this is that you don't really know if users of your class want to synchronize on your Whatever instances or not. If they do, they might interfere with the operation of the class itself. This way you've got your very own private lock which nobody can interfere with.

Categories

Resources