我是Java新手,我现在制作的游戏中玩家必须吃一些饼干。这些cookie是ArrayList的元素。这个ArrayList由两个线程修改: -one迭代它并删除已经吃过的cookie,使用Iterator.remove() - 每5秒向ArrayList添加一个cookie
有时候我得到一个ConcurrentModificationException,我知道它是因为Iterator.remove()的行为是未指定的,如果在迭代进行过程中以任何其他方式修改了底层集合" ;,如Sun的Java教程中所述。我该怎么办?
编辑:用
更新代码List<Cupcake> cake = Collections.synchronizedList(new ArrayList<Cupcake>());
这是Spawner:
public class CupcakeSpawner extends Thread {
private Background back;
public CupcakeSpawner(Background back) {
this.back = back;
}
public void run() {
while(true) {
if(back.getCake().size() < 15)
back.getCake().add(new Cupcake());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我的更新方法:
public void update() {
List<Cupcake> cake = back.getCake();
Iterator<Cupcake> itrC = cake.iterator();
while(itrC.hasNext()) {
Cupcake cupcake = (Cupcake)(itrC.next());
checkCollisionCup(cupcake);
if(cupcake.isEaten())
itrC.remove();
}
}
}
答案 0 :(得分:1)
ArrayList不是List的线程安全实现。
使用CopyOnWriteArrayList代替 - 如果在迭代时添加元素,则不会引发爆炸。
答案 1 :(得分:0)
正如@Bohemian所说,ArrayList不是线程安全的。
最好使用:
List list = Collections.synchronizedList(new ArrayList());
然后你要打电话给Iterator.remove()
synchronized (list) {
Iterator.remove()
}
希望这会对你有所帮助。
public class CupcakeSpawner extends Thread {
private Background back;
public CupcakeSpawner(Background back) {
this.back = back;
}
public void run() {
List cakes = back.getCake();
while(true) {
if(cakes.size() < 15){
synchronized (cakes) {
cakes.add(new Cupcake());
}
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
答案 2 :(得分:0)
如果基础数组发生了变化,那么我们就不能使用Iterator
的{{1}}:
ArrayList
当然,对于线程也是如此。
所以在你的情况下,你正在检查吃过的纸杯蛋糕(去除它们),同时还要在同一个系列中添加新的纸杯蛋糕。你所经历的是一种所谓的竞争条件。
解决此问题的一种方法是使用@Bohemian建议的public static void main(String[] args) {
List<Object> l = new ArrayList<>();
Iterator<Object> i = l.iterator();
l.add(new Object());
try {
System.out.println("I've added " + i.next());
} catch (ConcurrentModificationException e) {
System.out.println("Nooo!!!");
}
}
,但我不推荐它,因为每次修改都会导致创建一个新数组,这是一个性能开销(和内存)如果&#34;旧&#34;数组仍然被引用,例如由于CopyOnWriteArrayList
实例,则会出现问题。
解决此问题的另一种方法是在更新方法中使用count for循环。
Iterator
重要提示:使用此循环计数,您应该使用@Aalkhodiry建议的同步列表。
Fwiw:还有比这更多的线程......