package biz.boulter.state;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
import biz.boulter.sword.Game;
import biz.boulter.sword.Particle;
public class Menu implements State{
private ArrayList<Particle> particles = new ArrayList<Particle>();
boolean inLoop = false;
public Menu(){
}
@Override
public void render(Graphics2D g) {
if(!inLoop){
for(Particle p: particles){
p.render(g);
}
}
}
@Override
public void tick() {
if(!inLoop){
for(Particle p: particles){
p.tick();
}
}
}
@Override
public void keyPressed(int kc) {
}
@Override
public void keyReleased(int kc) {
}
@Override
public void mousePressed(int button, int x, int y) {
for(int i = 0; i<500; i++){
int rand;
if(Game.rand.nextBoolean()){
rand = Game.rand.nextInt(10)-11;
}else{
rand = Game.rand.nextInt(10)+1;
}
particles.add(new Particle(x, y, rand, Game.rand.nextInt(10)-11, new Color(Game.rand.nextInt(1000000000))));
}
}
@Override
public void mouseReleased(int button, int x, int y) {
}
}
嘿伙计这是我的代码,我不断收到ConcurrentModificationException。我知道这意味着两件事同时改变粒子变量。但是我应该如何添加到数组列表中。我看到一些论坛说使用迭代器,但这是为了删除不添加。
提前致谢!
编辑:
堆栈跟踪:
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at biz.boulter.state.Menu.render(Menu.java:21)
at biz.boulter.sword.Game.render(Game.java:43)
at biz.boulter.sword.Game.run(Game.java:136)
at java.lang.Thread.run(Unknown Source)
粒子类:
package biz.boulter.sword;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Particle {
private double x = 0;
private double y = 0;
private double xa = 0;
private double ya = 0;
private Color particleColour;
private Rectangle img;
public Particle(int x, int y, int xa, int ya, Color colour){
this.x = x;
this.y = y;
this.xa = xa;
this.ya = ya;
this.particleColour = colour;
img = new Rectangle(x, y, 5, 5);
}
public void render(Graphics2D g){
img.setBounds((int)Math.round(x), (int)Math.round(y), 5, 5);
g.setColor(particleColour);
g.fill(img);
}
public void tick(){
ya+=0.5;
if(xa < 0){
xa+=1;
}
if(xa > 0){
xa-=1;
}
x+=xa;
y+=ya;
}
}
答案 0 :(得分:3)
您有2个选项。如果可以,请将方法tick
,render
和mousePressed
标记为synchronized
。这将解决问题,但如果插入速度更快,这可能不是最好的解决方案。
另一种解决方案是改变
private ArrayList<Particle> particles = new ArrayList<Particle>();
到
private LinkedBlockingQueue<Particle> particles = new LinkedBlockingQueue<Particle>();
这是有效的,因为iterator
方法的documentation:
返回的迭代器是一个&#34;弱一致的&#34;将要的迭代器 永远不会抛出ConcurrentModificationException,并保证 在构造迭代器时存在的遍历元素, 并且可能(但不保证)反映任何修改 在施工之后。
答案 1 :(得分:2)
最简单的方法是在使用时锁定集合。
synchronized(particles) {
for(Particle p: particles){
p.tick();
}
}
和
Particle p = new Particle(x, y, rand, Game.rand.nextInt(10)-11, new Color(Game.rand.nextInt(1000000000)))
synchronized(particles) {
particles.add(p);
}
这样可以确保访问不是并发的。
CopyOnWriteArrayList的问题是写入很昂贵。顾名思义,每次更新都需要整个列表的副本。
BlockingQueue的问题在于它不是为迭代而设计的。它会起作用,但效率不高。
答案 2 :(得分:1)
为了避免在集合的迭代中出现问题和ConcurentModificationException
,你必须使用并发集合类。
对于ArrayList
,您可以尝试使用CopyOnWriteArrayList
ArrayList
的线程安全变体。
有关此内容的更多详细信息,请参阅此处:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
答案 3 :(得分:0)
你正试图改变数组的内部状态,在循环时,这是预期的行为。
一个快速(但有一些性能成本)是使用然后CopyOnWriteArrayList,请参阅链接条目, In what situations is the CopyOnWriteArrayList suitable?