更新值时出现 ConcurrentModificationException
ConcurrentModificationException while updating values
update
函数应通过调用函数 test
来更新 HashMap
中的每个值以确定新值。 test
函数 returns 为 1 或 0,具体取决于它周围的 8 locations/neighbors。虽然,每次程序进入更新功能时我都会得到一个 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;
}
你得到 ConcurrentModificationException
是因为你在迭代 Map
的同时修改它,这是不允许的。
您可以复制当前地图以进行迭代。
不是在同一张地图上进行操作,而是遍历一张地图并对第二张地图进行操作,然后使用第二张地图作为输出。
阅读 ConcurrentModificationException 以获得更多理解。
我不想回答您的问题(已经完成),而是想帮助您改进编码。
因为您使用的是 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()
进一步减少代码,这将获取值,并在必要时创建它。如果需要,请随意研究它;您需要了解 lambda。)
每个相邻小区的代码都是相同的。所以您可以将该代码放入它自己的函数中并调用它。
int sum = 0;
sum += neighbour_value(i-1, j-1);
sum += neighbour_value(i, j-1);
sum += neighbour_value(i+1, j-1);
... etc ...
希望对您有所帮助。
编码愉快。
update
函数应通过调用函数 test
来更新 HashMap
中的每个值以确定新值。 test
函数 returns 为 1 或 0,具体取决于它周围的 8 locations/neighbors。虽然,每次程序进入更新功能时我都会得到一个 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;
}
你得到 ConcurrentModificationException
是因为你在迭代 Map
的同时修改它,这是不允许的。
您可以复制当前地图以进行迭代。 不是在同一张地图上进行操作,而是遍历一张地图并对第二张地图进行操作,然后使用第二张地图作为输出。
阅读 ConcurrentModificationException 以获得更多理解。
我不想回答您的问题(已经完成),而是想帮助您改进编码。
因为您使用的是 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()
进一步减少代码,这将获取值,并在必要时创建它。如果需要,请随意研究它;您需要了解 lambda。)
每个相邻小区的代码都是相同的。所以您可以将该代码放入它自己的函数中并调用它。
int sum = 0;
sum += neighbour_value(i-1, j-1);
sum += neighbour_value(i, j-1);
sum += neighbour_value(i+1, j-1);
... etc ...
希望对您有所帮助。
编码愉快。