更新值时出现ConcurrentModificationException

时间:2018-02-05 03:02:43

标签: java hashmap concurrentmodification

update函数应通过调用函数HashMap来更新test中的每个值,以确定新值。 test函数返回1或0,具体取决于它周围的8个位置/邻居。虽然,每次程序进入更新功能时我都会得ConcurrentModificationException

private static void update(){
   for(Cell e : map.keySet()){
       map.put(e,test(e.getX(),e.getY()));
  }
}

private static int test(int i, int j){
    //count alive neighbors
    int sum = 0;
    if(map.get(new Cell(i-1, j - 1)) == null){
        map.put(new Cell(i-1, j - 1), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i-1, j - 1));
    } else {
        sum += map.get(new Cell(i-1, j - 1));
    }

    if(map.get(new Cell(i, j - 1)) == null){
        map.put(new Cell(i, j - 1), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i, j - 1));
    } else {
        sum += map.get(new Cell(i, j - 1));
    }

    if(map.get(new Cell(i + 1, j - 1)) == null){
        map.put(new Cell(i + 1, j - 1), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i + 1, j - 1));
    } else {
        sum += map.get(new Cell(i + 1, j - 1));
    }

    if(map.get(new Cell(i + 1, j)) == null){
        map.put(new Cell(i + 1, j), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i + 1, j));
    } else {
        sum += map.get(new Cell(i + 1, j));
    }

    if(map.get(new Cell(i + 1, j + 1)) == null){
        map.put(new Cell(i + 1, j + 1), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i + 1, j + 1));
    } else {
        sum += map.get(new Cell(i + 1, j + 1));
    }

    if(map.get(new Cell(i, j + 1)) == null){
        map.put(new Cell(i, j + 1), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i, j + 1));
    } else {
        sum += map.get(new Cell(i, j + 1));
    }

    if(map.get(new Cell(i - 1, j + 1)) == null){
        map.put(new Cell(i - 1, j + 1), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i - 1, j + 1));
    } else {
        sum += map.get(new Cell(i - 1, j + 1));
    }

    if(map.get(new Cell(i - 1, j)) == null){
        map.put(new Cell(i - 1, j), ((Math.random()<0.5)?0:1));
        sum += map.get(new Cell(i - 1, j));
    } else {
        sum += map.get(new Cell(i - 1, j));
    }

    //return to be alive or dead
    int temp = 0;
    if(map.get(new Cell(i,j)) == 1){
        if(sum < 2){
            temp = 0;
        } else if(sum == 2 || sum == 3){
            temp = 1;
        } else if(sum > 3){
            temp = 0;
        }
    } else {
        if(sum == 3){
            temp = 1;
        }
    }
    return temp;
}

2 个答案:

答案 0 :(得分:3)

我不想回答您的问题(已经完成),而是希望帮助您改进编码。

因为您使用的是map.get(new Cell(i-1, j-1)),所以我希望您提供了Cell#hashcode()Cell#equals()的实施方案。如果没有,请阅读HashMap的工作原理,然后立即实施这些方法。

请考虑以下代码:

if (map.get(new Cell(i-1, j-1)) == null){
    map.put(new Cell(i-1, j-1), ((Math.random()<0.5)?0:1));
    sum += map.get(new Cell(i-1, j-1));
}
else{
    sum += map.get(new Cell(i-1, j-1));
}

在这里,您要拨打new Cell(i-1, j-1)四次!据推测,这些Cell对象中的每一个都将彼此相等,但为什么不创建它一次,并将其重用于后续调用:

Cell neighbour = new Cell(i-1, j-1);
if (map.get(neighbour) == null){
    map.put(neighbour, ((Math.random()<0.5)?0:1));
    sum += map.get(neighbour);
}
else{
    sum += map.get(neighbour);
}

垃圾收集器现在会更快乐一些。但是,我仍然看到3次拨打map.get(neighbour)!为什么?最后两个在sum += map.get(neighbour);语句的每个分支的末尾都是相同的if。如果我们将其移出声明,事情会变得更好!

Cell neighbour = new Cell(i-1, j-1);
if (map.get(neighbour) == null){
    map.put(neighbour, ((Math.random()<0.5)?0:1));
}
sum += map.get(neighbour);

这是一个相当大的改进。

(您可以使用computeIfAbsent()进一步减少代码,这将获取值,并在必要时创建它。如果需要,可以随意研究它;您需要了解lambdas。)

每个相邻小区的代码是相同的。因此,您可以将该代码放入其自己的函数中并调用它。

int sum = 0;
sum += neighbour_value(i-1, j-1);
sum += neighbour_value(i,   j-1);
sum += neighbour_value(i+1, j-1);
... etc ...

希望有所帮助。

快乐的编码。

答案 1 :(得分:1)

您正在获取 $(document).ready(function(){ $("#tambah").click(function () { var markup = "<tr><td><input type = \"number\" ID = \"no\" placeholder = \"1\"/></td><td><input type = \"text\" ID = \"tahapan\" placeholder = \"Tahapan 1\"/></td><td><input type = \"text\" ID = \"suboutput\" placeholder = \"Sub-Output 1\"/></td></tr>"; $('#table2 tbody').append(markup); }); }); ,因为您在迭代时正在修改ConcurrentModificationException,这是不允许的。

您可以制作当前地图的副本以进行迭代。 而不是在同一个地图上进行操作,迭代一个并对第二个进行操作,然后使用第二个地图作为输出。

了解ConcurrentModificationException以获取更多理解。