Concurrency and Calendar classes

Posted by fbielejec on Stack Overflow See other posts from Stack Overflow or by fbielejec
Published on 2011-06-23T13:44:01Z Indexed on 2011/06/23 16:22 UTC
Read the original article Hit count: 219

Filed under:
|
|

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?

© Stack Overflow or respective owner

Related posts about java

Related posts about concurrency