E/AndroidRuntime: FATAL EXCEPTION: main
Process: dev.game.adventure, PID: 21482
java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966)
at java.util.LinkedList$ListItr.next(LinkedList.java:888)
at dev.game.adventure.Troll.wakeup(Troll.java:32)
at dev.game.adventure.Simulation$1.run(Simulation.java:29)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
我在模拟器中运行一段时间后得到了上面的跟踪。这是什么意思?我该如何解决?我甚至无法复制它,因为它只会在一段时间后发生。这是违法的代码:
thing = i.next();
(Troll.java:32)
Class Troll.java
package dev.game.adventure;
import android.os.Handler;
import android.widget.Toast;
import java.util.*;
public class Troll extends WalkingPerson {
private boolean hasCoke = false;
private AdventureActivity target;
Troll(Simulation s, World world, String name, AdventureActivity app) {
super(s, world, name, R.mipmap.lobgoblin, app);
this.target = app;
goTo("Kulverten", target);
}
public void wakeup() {
Person victim = (Person) (place.persons.toArray()[((int) (Math.random() * place.persons
.size()))]);
if (victim instanceof Troll) { // Don't commit suicide
} else {
say("Victim is " + victim.getName() + ".", target);
Thing thing;
for (Iterator<Thing> i = victim.things.iterator(); i.hasNext(); ) {
thing = i.next();
if (thing instanceof CocaCola) {
hasCoke = true;
victim.things.remove(thing);
world.update(place, target);
say("Now I take your Coca Cola!", target);
//TODO: Actually take the drink
} else {
drop(thing.name, target); // drop all items so that the key doesn't end up in heaven
}
}
if (!hasCoke) {
say("Now I kill you!", target); // TODO: Take all the items of the victim
// this.getWorld().playAtPlace(place, "effects/gong");
final Person victim2 = victim;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
victim2.goTo("Heaven", target);
world.update(victim2.place, target);
world.sayAtPlace(victim2.place, "-- Game Over --", target);
if (victim2.getName().equals("You")) {
target.ag.setBackground(world.getPlace("Heaven").getImage());
final Toast toast = Toast.makeText(target.ag.getContext(), "GAME OVER!\n", Toast.LENGTH_LONG);// duration);
toast.show();
}
}
}, 1500);
}
}
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(Math.random() > 0.3)
go(place.randomDoor(), target);
}
}, 2500);
s.wakeMeAfter(this, (80 + Math.random() * 1000));
}
}
答案 0 :(得分:1)
替换:
victim.things.remove(thing);
使用:
i.remove();
从正在迭代的列表中删除项目的唯一安全方法是使用迭代器。
如果使用list.remove()
方法执行此操作,迭代器很难更新其内部状态以正确处理删除。因此,它只是放弃了#34; - 它会导致ConcurrentModificationException
说'#34;我处于无效状态,我无法从此恢复&#34;。
顺便说一句,我认为你偶尔看到这个的原因是因为列表中的项目排序。
hasNext
中LinkedList.Itr
的实施只会检查:
return nextIndex < size;
其中nextIndex
是迭代器的成员变量,在next()
中更新为要返回的下一个元素的索引。
如果您移除包含list.remove
的项目,则size
会减少。因此,如果您使用list.remove
删除的项目恰好是列表中的最后一项(或倒数第二项),hasNext()
为假,那么您就不会调用next()
并获得CME。
值得注意的是,如果你确实删除了倒数第二个元素,那么循环会在处理列表中的最终项之前中断,没有任何异常。这是一种阴险的行为,并且会成为一个真正令人头疼的问题。只需通过迭代器从列表中删除它就可以避免它。
答案 1 :(得分:1)
您可以通过以下方式简单地重现此异常:
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,5));
Iterator<Integer> iter = list.iterator();
list.remove(0);
iter.next();
基本上,您不能使用迭代器迭代列表,同时从列表中删除内容。
// 1. you have an iterator here
for (Iterator<Thing> i = victim.things.iterator(); i.hasNext(); ) {
// 3. on the next iteration, you read from i and BOOM!
thing = i.next();
if (thing instanceof CocaCola) {
hasCoke = true;
// 2. you removed a thing here
victim.things.remove(thing);
world.update(place, target);
say("Now I take your Coca Cola!", target);
//TODO: Actually take the drink
} else {
drop(thing.name, target); // drop all items so that the key doesn't end up in heaven
}
}
要实际删除内容,您应该在迭代器上调用remove
:
i.remove() // replace things.remove with this