I have LinkedList of objects and an iterator. I know that this ConcurrentModificationException is thrown when you try to modify the list while running the iterator. But in my case, I don't understand where this modification is being done.
The iterator looks like this :
private static void insertTasks(Task t) {
if(eventQueue.size() == 0) {
eventQueue.addFirst(tsk);
return;
}
int pos = 0;
while (itr.hasNext()){
//The line below throws the exception
if (t.getArrivalTime() <= itr.next().getArrivalTime() )
{
break;
}
pos++;
}
}
I am calling this insertTasks method from another method as shown below :
tsk = null;
tsk = new Task(1,"P1",1,4.0f,1.5f,0.0f,8.0f);
insertTasks(tsk);
tsk = null;
tsk = new Task(0,"P0",2,5.0f,2.5f,1.0f,10.0f);
insertTasks(tsk);
The getArrivalTime in the Task objects looks like :
public float getArrivalTime() { return arrivalTime; }
My question is, where am I doing this modification ? The while loop where I run this iterator is not doing any modification. Does it ?
Am I missing something ?
I reckon the problem is that itr is a static field in your class and that's creating the issue, as you're adding an element to eventQueue in your second call to insertTasks().
Avoid static fields... program yourself to fear them and avoid them as much as you can :). They evil, and OO unfriendly.
Related
What I try to do - call twice the a method on two different List:
Element P must be removed if isTranslation() is true.
Element P and the following element must be removed if the isTitle() is true;
I'm running the following code:
private List<P> nlPars; //initialised in constructor
private List<P> enPars; //initialised in constructor
public void build(){
...
removeHeaders(nlPars); //first time calling, no problem
removeHeaders(enPars); //second time calling, throws ConcurrentModificationException
...
}
calling this method:
#VisibleForTesting
void removeHeaders(final List<P> pars) {
pars.removeIf(p -> isTranslation(p));
for (final ListIterator<P> it = pars.listIterator(); it.hasNext(); ) {
if (isTitle(it.next())) {
it.remove();
if (it.hasNext()) {
it.next();
it.remove();
}
break;
}
}
}
I have no idea why. The debugger tells me that on the second time, the pars.listIterator() cannot be evaluated/throws ConcurrentModificationException.
I've been looking for hours now to fix this. Maybe someone can help!
Regards,
Bart
I solved it, the problem was not here. The problem was in the construction of enPars en nlPars. They were derived like nlPars = pars.subList(...). That's fine, but they are views on the pars list and the iterator is the same, hence the problem.
Changing it solved the issue:
enPars = new ArrayList<P>(pars.subList(0, i));
I'm in this situation: if I find a specific value in a HashSet, I have to update a field, clear the set and return the field.
Here one example:
static Set<Integer> testSet = new HashSet<>();
static Integer myField = null; // the field could be already != null
public static int testClearSet()
{
for (int i = 0; i < 100; i++) { // this is just for the test
testSet.add(i);
}
for (Integer n : testSet) {
if (n == 50) {
myField = n;
testSet.clear();
return myField;
}
}
return -1;
}
I'm wondering if doing this to the set it's safe, considering the fact that later on I should reuse the set.
I'm asking this, because I knew that to make changes over a Collection while iterating, is not a "good practice", but this case I think is a little bit different.
A possible solution would be:
boolean clear = false;
for (Integer n : testSet) {
if (n == 50) {
myField = n;
clear = true;
break;
}
}
if (clear) {
testSet.clear();
return myField;
}
So, which one is the right way?
It should be safe to remove elements from a set when using an explicit iterator. Hence the following should be safe:
Iterator<Integer> iterator = testSet.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element.intValue() == 50) {
testSet.clear();
break;
}
}
A ConcurrentModificationException is only thrown if you continue iterating after changing it manually.
What you do is change it and abort iterating, so it should be 100% safe (regardless of the for-each implementation).
The real issue is, the readability of the code. A piece of code should ideally do one job, and if this job is complicated, split it up. In particular, your code has two parts, a condition and an action:
if (some condition) do some action
So:
public static int testClearSet() {
if (setConatins(50)) {
myField = 50;
testSet.clear();
return myField;
}
return -1;
}
private static boolean setConatins(int searchFor) {
for (Integer n : testSet) {
if (n == searchFor) {
return true;
}
}
return false;
}
The latter method can be replaced with a single API call, for you to figure out.
If you know that your Set changing only in one thread, so you can clean it like in first example.
Method clear() does not throw ConcurrentModificationException.
Both your code will work.
There is indeed a restriction in modifying the collection when u iterate using fail fast iterators. That means, iterating using fail fast iterator will fail if there is any modification in the collection after the iterator was created. All the default iterators that is returned by java collection classes are fail-fast iterators.
private void removeDataTest (Collection<String> c, String item) {
Iterator<String> iter = c.iterator(); //Iterator is created.
while (iter.hasNext()) {
String data = iter.next();
if (data.equals(item)) {
//c.remove(data); //Problem. Directly modifying collection after this iterator is created. In the next iteration it will throw concurrent modification exception.
iter.remove(); //This is fine. Modify collection through iterator.
//c.clear(); break; //This is also should be okay. Modifying the collection directly, but after that it is breaking out and not using the iterator.
}
}
}
In your code, u don't continue iteration after the set is modified. So should be fine.
I have set of connection objects (library code I cannot change) that have a send method. If the sending fails, they call back a generic onClosed listener which I implement that calls removeConnection() in my code, which will remove the connection from the collection.
The onClosed callback is generic and can be called at any time. It is called when the peer closes the connection, for example, and not just when a write fails.
However, if I have some code that loops over my connections and sends, then the onClosed callback will attempt to modify a collection during iteration.
My current code creates a copy of the connections list before each iteration over it; however, in profiling this has shown to be very expensive.
Set<Connection> connections = new ....;
public void addConnection(Connection conn) {
connections.add(conn);
conn.addClosedListener(this);
}
#Override void onClosed(Connection conn) {
connections.remove(conn);
}
void send(Message msg) {
// how to make this so that the onClosed callback can be safely invoked, and efficient?
for(Connection conn: connections)
conn.send(msg);
}
How can I efficiently cope with modifying collections during iteration?
To iterate a collection with the concurrent modification without any exceptions use List Iterator.
http://www.mkyong.com/java/how-do-loop-iterate-a-list-in-java/ - example
If you use simple for or foreach loops, you will receive ConcurrentModificationException during the element removing - be careful on that.
As an addition, you could override the List Iterator with your own one and add the needed logic. Just implement the java.util.Iterator interface.
A ConcurrentSkipListSet is probably what you want.
You could also use a CopyOnWriteArraySet. This of course will still make a copy, however, it will only do so when the set is modified. So as long as Connection objects are not added or removed regularly, this would be more efficient.
You can also use ConcurrentHashMap.
ConcurrentHashMap is thread-safe, so you don't need to make a copy in order to be able to iterate.
Take a look at this implementation.. http://www.java2s.com/Tutorial/Java/0140__Collections/Concurrentset.htm
I would write a collection wrapper that:
Keeps a set of objects that are to be removed. If the iteration across the underlying collection comes across one of these it is skipped.
On completion of iteration, takes a second pass across the list to remove all of the gathered objects.
Perhaps something like this:
class ModifiableIterator<T> implements Iterator<T> {
// My iterable.
final Iterable<T> it;
// The Iterator we are walking.
final Iterator<T> i;
// The removed objects.
Set<T> removed = new HashSet<T>();
// The next actual one to return.
T next = null;
public ModifiableIterator(Iterable<T> it) {
this.it = it;
i = it.iterator();
}
#Override
public boolean hasNext() {
while ( next == null && i.hasNext() ) {
// Pull a new one.
next = i.next();
if ( removed.contains(next)) {
// Not that one.
next = null;
}
}
if ( next == null ) {
// Finished! Close.
close();
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
// Close down - remove all removed.
public void close () {
if ( !removed.isEmpty() ) {
Iterator<T> i = it.iterator();
while ( i.hasNext() ) {
if ( removed.contains(i.next())) {
i.remove();
}
}
// Clear down.
removed.clear();
}
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
public void remove(T t) {
removed.add(t);
}
}
public void test() {
List<String> test = new ArrayList(Arrays.asList("A","B","C","D","E"));
ModifiableIterator i = new ModifiableIterator(test);
i.remove("A");
i.remove("E");
System.out.println(test);
while ( i.hasNext() ) {
System.out.println(i.next());
}
System.out.println(test);
}
You may need to consider whether your list could contain null values, in which case you will need to tweak it somewhat.
Please remember to close the iterator if you abandon the iteration before it completes.
E.g.
I have a queue
void someMethod() {
history.add(new Sample(time, data));
...
traverse(history);
}
void traverse(Queue<Sample> history) {
for(int i=0; i<history.size(); i=i+10) {
history.get(i)... // ???
}
}
class Sample {
long time;
double data;
}
The concerns are that
I don't want to destroy this queue by calling traverse().
Traverse the queue in a given step, say 10 here.
Any simple and nice solution?
for (Sample s : history)
doStuff(s);
This is called the enhanced for-loop; you can read more about it here.
Queue implements Iterable, so a simple loop will traverse it:
for (Sample sample : history)
An Iterator is another way to do it, with more control (can destroy it if you want to), but more verbose.
If you just want to iterate, use a for-each loop or directly a for loop with an Iterator. This doesn't consume the queue.
If you need to iterate with a step, you can use this pattern. It works generally with any Iterable. Putting the skipping into a separate reusable method makes the code more clear than having two nested for loops.
public static void main(String[] args) {
Queue<Sample> history = ...
int step = 10;
for (Iterator<Sample> it = history.iterator();
it.hasNext(); skip(it, step - 1)) {
// note that we skipped 1 less elements than the size of the step
Sample sample = it.next();
// stuff
}
}
static void skip(Iterator<?> iterator, int count) {
for (int i = 0; i < count && iterator.hasNext(); i++) {
iterator.next();
}
}
LinkedList<Sample> h = (LinkedList<Sample>) history;
for(int i=0; i < h.size(); i+=step) {
h.get(i).memory ...
}
I just realized this approach, haven't tried it yet.
As nullptr pointed out, the condition for above code is that the Queue is implemented as a LinkedList. (which is my case: Queue<Sample> history = new LinkedList<Sample>();)
What I am trying to do is save a Move objects into a Vector called topMoves. There will be many Move objects which is why I create the object within the loop.
The pastPriceMap stores prices for stocks at some past time (in this case one minute ago). The currPriceMap stores price for stocks some time within the last second.
I get the following exception:
Exception in thread "Timer-0" java.util.NoSuchElementException
This is the line that is causing the problem:
amove.setInitPrice(pastPriceMap.get(iter.next()));
The code snippet is below. When I do the System.out.println statements I get the expected output:
Iterator<String> iter = sortedTopCodes.iterator();
while(iter.hasNext()){
System.out.println(currPriceMap.get(iter.next()));
System.out.println(pastPriceMap.get(iter.next()));
Move amove = new Move();
amove.setSecCode(iter.next());
amove.setPrice(currPriceMap.get(iter.next()));
amove.setInitPrice(pastPriceMap.get(iter.next()));
topMoves.add(amove);
}
return topMoves;
The Move class looks like this:
private String secCode;
private double price;
private double initPrice;
public String getSecCode() {
return secCode;
}
public void setSecCode(String secCode) {
this.secCode = secCode;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getInitPrice() {
return initPrice;
}
public void setInitPrice(double lastPrice) {
this.initPrice = lastPrice;
}
Short answer:
For each call to hasNext() there should be only one call to next()
In your code you have 5 next() with only one hasNext()
Here, read this: http://java.sun.com/javase/6/docs/api/java/util/Iterator.html
EDIT
Longer answer:
Basically an iterator is used to ... well iterate the elements of "something" tipically a collection but it could be anything ( granted that anything returns an Iterator ).
Since you may not know how many elements does that "anything" have, there must be a way to stop iterating right? ( if it was an array, you can tell by the length property, but the iterator is used to "encapsulate" the data structure used in the implementation ) Anyway.
The iterator API defines these two methods
-hasNext(): boolean
-next(): Object ( or <E> since Java 1.5 )
So the typical idiom is this:
while( iterator.hasNext() ) { // reads: while the iterator has next element
Object o = iterator.next(); // give me that element
}
What happens if the iterator has only two items?
while( iterator.hasNext() ) { // the first time will return true, so the next line will be executed.
Object o = iterator.next(); // give me that item. ( 1st element )
Object b = iterator.next(); // oops dangerous by may work ... ( 2nd element )
Object c = iterator.next(); // eeeerhhh... disaster: NoSuchElementException is thrown.
}
This is what is happening to you. You did not verify if the iterator has another element, you just retrieve it. If the iterator happens to have some elements, it may work for a while but there will be a time ( as you just saw ) when it fails.
By the way, DO NOT even think in catching NoSuchElementException. That's a runtime exception and it indicates that something in your code logic should be fixed.
See this answer to know more about the exceptions.
Here is a version using the new for loops:
for ( String secCode : secCodeList ) {
System.out.println(currPriceMap.get(secCode));
System.out.println(pastPriceMap.get(secCode));
Move amove = new Move();
amove.setSecCode(secCode);
amove.setPrice(currPriceMap.get(secCode));
amove.setInitPrice(pastPriceMap.get(secCode));
topMoves.add(amove);
}
in the older fashion :
String secCode = null;
for ( Iterator<String> it = secCodeList.iterator(); it.hasNext() ) {
secCode = it.next();
System.out.println(currPriceMap.get(secCode));
System.out.println(pastPriceMap.get(secCode));
Move amove = new Move();
amove.setSecCode(secCode);
amove.setPrice(currPriceMap.get(secCode));
amove.setInitPrice(pastPriceMap.get(secCode));
topMoves.add(amove);
}
// while there are more lines
while(scanner.hasNextLine())
{
final String line;
final String[] words;
// get the next line
line = scanner.nextLine();
// break the line up into the words (\\s+ should break it up via whitespace)
words = line.split("\\s");
if(words.length != 5)
{
throw new WhateverExceptionMakesSense(line + " must contain 5 words");
}
System.out.println(currPriceMap.get(words[0]));
System.out.println(pastPriceMap.get(words[1]));
Move amove = new Move();
amove.setSecCode(words[2]);
amove.setPrice(currPriceMap.get(words[3]));
amove.setInitPrice(pastPriceMap.get(words[4]));
topMoves.add(amove);
}