I have a thread (class implementing runnable, called AnalyzeTree) organised around a hash map (ConcurrentMap slicesMap). The class goes through the data (called trees here) in the large text file and parses the geographical coordinates from it to the HashMap. The idea is to process one tree at a time and add or grow the values according to the key (which is just a Double value representing time).
The relevant part of code looks like this:
// grow map entry if key exists
if (slicesMap.containsKey(sliceTime)) {
double[] imputedLocation = imputeValue(
location, parentLocation, sliceHeight,
nodeHeight, parentHeight, rate,
useTrueNoise, currentTreeNormalization,
precisionArray);
slicesMap.get(sliceTime).add(
new Coordinates(imputedLocation[1],
imputedLocation[0], 0.0));
// start new entry if no such key in the map
} else {
List<Coordinates> coords = new ArrayList<Coordinates>();
double[] imputedLocation = imputeValue(
location, parentLocation, sliceHeight,
nodeHeight, parentHeight, rate,
useTrueNoise, currentTreeNormalization,
precisionArray);
coords.add(new Coordinates(imputedLocation[1],
imputedLocation[0], 0.0));
slicesMap.putIfAbsent(sliceTime, coords);
// slicesMap.put(sliceTime, coords);
}// END: key check
And the class is called like this (executor is ExecutorService executor = Executors.newFixedThreadPool(NTHREDS) ):
mrsd = new SpreadDate(mrsdString);
int readTrees = 1;
while (treesImporter.hasTree()) {
currentTree = (RootedTree) treesImporter.importNextTree();
executor.submit(new AnalyzeTree(currentTree,
precisionString, coordinatesName, rateString,
numberOfIntervals, treeRootHeight, timescaler,
mrsd, slicesMap, useTrueNoise));
// new AnalyzeTree(currentTree, precisionString,
// coordinatesName, rateString, numberOfIntervals,
// treeRootHeight, timescaler, mrsd, slicesMap,
// useTrueNoise).run();
readTrees++;
}// END: while has trees
Now this is running into troubles when executed in parallel (the commented part running sequentially is fine), I thought it might throw a ConcurrentModificationException, but apparently the problem is in mrsd (instance of SpreadDate object, which is simply a class for date related calculations).
The SpreadDate class looks like this:
public class SpreadDate {
private Calendar cal;
private SimpleDateFormat formatter;
private Date stringdate;
public SpreadDate(String date) throws ParseException {
// if no era specified assume current era
String line[] = date.split(" ");
if (line.length == 1) {
StringBuilder properDateStringBuilder = new StringBuilder();
date = properDateStringBuilder.append(date).append(" AD")
.toString();
}
formatter = new SimpleDateFormat("yyyy-MM-dd G", Locale.US);
stringdate = formatter.parse(date);
cal = Calendar.getInstance();
}
public long plus(int days) {
cal.setTime(stringdate);
cal.add(Calendar.DATE, days);
return cal.getTimeInMillis();
}// END: plus
public long minus(int days) {
cal.setTime(stringdate);
cal.add(Calendar.DATE, -days); //line 39
return cal.getTimeInMillis();
}// END: minus
public long getTime() {
cal.setTime(stringdate);
return cal.getTimeInMillis();
}// END: getDate
}
And the stack trace from when exception is thrown:
java.lang.ArrayIndexOutOfBoundsException: 58
at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:454)
at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2098)
at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2013)
at java.util.Calendar.setTimeInMillis(Calendar.java:1126)
at java.util.GregorianCalendar.add(GregorianCalendar.java:1020)
at utils.SpreadDate.minus(SpreadDate.java:39)
at templates.AnalyzeTree.run(AnalyzeTree.java:88)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:636)
If a move the part initializing mrsd to the AnalyzeTree class it runs without any problems - however it is not very memory efficient to initialize class each time this thread is running, hence my concerns. How can it be remedied?