I get this exception when I start a second timer after canceling the first one.Both timers uses a separate ArrayList
and iterates through it. No removal/modification is performed on the list, still I get concurrent modification exception when I stop the first timer and start the second one right away. If I wait few seconds before initiating the second timer, then it works fine.I ended up making a copy of the incoming list on both timers, passed the copy to the timer, still gets the error.Not sure why I get the error even though I am merely iterating through the list and writing the data to a flat file.
This is my code:
Timer 1
private void timerwork(final List<Object> list) throws IOException {
timer = new Timer();
final List<Object> taskList = list;
timer.scheduleAtFixedRate(new CustomTimerTask(taskList) {
@Override
public void run() {
if (taskList != null && !taskList.isEmpty()) {
synchronized (taskList) {
for (Object o: taskList) {
try {
valueIncrementOperation(o);// this method takes each obect,
does some logic and writes to a flat file,
it does not modify the object itself,
but just reads it and do some ext calculation
on some local variables
} catch (IOException e) {
timer.cancel();
timer.purge();
throw new RuntimeException(e.getMessage(), e);
}
}
//once exited out of the loop,
it copies the flat file to another file
try {
copyFileUsingFileChannels(source, finaldest);
} catch (IOException e) {
}
}
public synchronized void valueIncrementOperation(Object o)
throws IOException {
DataInputStream d = new DataInputStream(new FileInputStream(sourcefile));
DataOutputStream out = new DataOutputStream(new FileOutputStream(
tempfile));
initialValue = Long.parseLong(o.getDefaullt_value());
String count;
String t;
while ((count = d.readLine()) != null) {
String u = count.toUpperCase();
String[] z = u.split(" ");
if (z[0].contains(o.getO())) {
............................
out.writeBytes(t + "\n");
}
d.close();
out.close();
copyFileUsingFileChannels(source, initialDest);
}
CustomTimerTask code:
public class CustomTimerTask extends TimerTask {
private List<Object> list = new ArrayList<Object>();
public CustomTimerTask(List<Object> list) {
this.list = list;
}
@Override
public void run() {
// TODO Auto-generated method stub
}
Timer 2 has similar logic: ie, makes copy of incoming list before passing to timer2. Still I get this error:
Exception in thread "Timer-0" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Work around is to wait few seconds before starting timer2. Is there a better way to address this scenario?
this.list = list;
doesn't make a copy of the list, it just makes a new reference to the same list. – DavidC Nov 29 '13 at 18:04final List<Object> taskList = list;
and pass intaskList
to constructor – decent guy Nov 29 '13 at 18:07final List<Object> taskList = new ArrayList<Object>(list);
to make a copy, or use a copy-on-write implementation as @Gennaro mentioned. – DavidC Nov 29 '13 at 18:09