java - 并发和日历类

标签 java concurrency hashmap

我有一个围绕 HashMap (ConcurrentMap> slicesMap)组织的线程(实现可运行的类,称为AnalyzeTree)。该类遍历大型文本文件中的数据(此处称为树),并将地理坐标从其中解析到 HashMap。这个想法是一次处理一棵树,并根据键(只是代表时间的 Double 值)添加或增长值。

代码的相关部分如下所示:

// 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

该类的调用方式如下(执行器为 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

现在这在并行执行时遇到了麻烦(按顺序运行的注释部分很好),我认为它可能会抛出 ConcurrentModificationException,但显然问题出在 mrsd (SpreadDate 对象的实例,它只是一个类)日期相关的计算)。

SpreadDate 类如下所示:

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
}

以及抛出异常时的堆栈跟踪:

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)

如果将初始化 mrsd 的部分移至AnalyzeTree 类,它运行时不会出现任何问题 - 但是每次该线程运行时初始化类的内存效率不是很高,因此我担心。该如何补救?

最佳答案

日历和日期是可变类的两个示例。您似乎在 ExecutorService 之间共享它们,并且您看到的结果是意外的。我建议为每个线程创建一个 SpreadDate 对象的新实例。

关于java - 并发和日历类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6455027/

相关文章:

java - 将 json 时间戳转换为普通 java 时间戳

java - FetchType = Lazy 且可选 = false 在 JPA 中不起作用

java - 使用 Hibernate 通过公共(public)桥接表映射 3 个实体

java - 软删除包位置

java - 执行器服务 : FIFO ordering by key

java - 为什么这个 Hashmap 迭代不起作用?我收到 NullPointerException

java - jvm重排序/可见性效果测试

go - goroutine 没有输出

java - 使用 Java 8 流时更新现有的 Map 对象

java - 使用HashMap实现HashSet有问题吗?