我正在创建一个Swing应用程序来制作游戏。它在屏幕外的随机位置创建图像,当它们离开屏幕时我想删除它们。请查看代码段:
public void checkTrolls(){ //CAUSES EXCEPTION ERROR WHEN SPRITE EXIT SCREEN
for(AutomatedSprite a : trolls){
if(a.getX() < 0 - a.getImage().getWidth())
trolls.remove(a);
if(a.getY() < 0 - a.getImage().getWidth())
trolls.remove(a);
if(a.getX() > 800)
trolls.remove(a);
if(a.getY() > 600)
trolls.remove(a);
}
}
@Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while(true){
dodger.update(); //update sprite
if(trolls.size() != 6){
trolls.add(new AutomatedSprite("images/troll_face.png"));
}
for(Sprite troll : trolls){
troll.update(); //UPDATES MY SPRITES
}
checkTrolls(); //CHECKS TROLLS EXITING THE SCREEN
repaint();
for(Sprite troll : trolls){
System.out.println("X: " + troll.getX());
System.out.println("Y: " + troll.getY());
}
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = timeDiff - DELAY;
if(sleep < 0)
sleep = 5;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) { e.printStackTrace(); }
beforeTime = System.currentTimeMillis();
}
}
巨魔是AutomatedSprites的Vector,当他们离开屏幕时我得到一个ConcurrentModificationException,显然我无法从我的向量中删除实例。
因此,当线程更新所有精灵时,我似乎无法从向量中删除任何内容,有没有办法暂停我的线程以便我可以删除精灵?
P.S:如果我错过了一些内容,这是整个班级:Pastebin
答案 0 :(得分:5)
在迭代它时无法从集合中删除,对于单线程环境和多线程环境都是如此。 syncrhonized
仍会导致问题,Thread.sleep也是如此。使用和迭代器并删除该方式。
public void checkTrolls(){
for(Iterator<AutomatedSprite> itr = trolls.iterator(); itr.hasNext();){
AutomatedSpring nextElemnt = itr.next();
if(youShouldRemoveTheSprite){
itr.remove();
}
}
}
所以在这里你使用你的巨魔集合提供的迭代器。而且你要求Iterator安全地从集合中删除对象。
现在,如果你执行了多个线程的checkTrolls,那么你需要进行同步。你可以这样做
public synchronized void checkTrolls(){ ...
根据您最近的评论/链接修改 。
并不是将Iterator.next()赋值给变量,而是多次调用iterator.next()。每次调用next()
时,都会将迭代器移动到List的下一个元素。因此,在一个循环迭代结束时,您将迭代器移动到列表中的第6个元素。如果你正在索引它,它看起来像:
for(Iterator<AutomatedSprite> itr = trolls.iterator(); itr.hasNext(); ){
if(trolls.get(0).getX() < 0 - trolls.get(1).getImage().getWidth() ||
trolls.get(2).getY() < 0 - trolls.get(3).getImage().getWidth() ||
trolls.get(4).getX() > 800 ||
trolls.get(5).getY() > 600){
trolls.remove(trolls.get(5));
}
注意这个例子:在0,1,2,3,4 ...的索引仅用于演示,实际上它将是i = 0; start for loop trolls.get(i ++)。getX(),trolls.get(i ++)。getY()等等。如果您的列表是10,000,那么最终会得到NoSuchElementException
例如,如果你只有3个巨魔,一旦你到达第4个itr.next(),你将得到NoSuchElementException。因此,您需要将next()元素存储在变量中并处理该变量,以便itr.hasNext();正确返回,itr.remove()也能正常工作。
答案 1 :(得分:2)
在checkTrolls()
中,您在迭代它时从Vector
删除元素。这将导致ConcurrentModificationException
来自Vector的javadoc
此类的迭代器和listIterator返回的迭代器 方法是快速失败的:如果向量在任何结构上被修改 创建迭代器之后的时间,除了通过之外的任何方式 迭代器自己删除或添加方法,迭代器会抛出一个 ConcurrentModificationException的。
几种选择:
创建一个元素列表,在完全迭代后删除和删除它们。
使用线程安全List
实施,例如CopyOnWriteArrayList
答案 2 :(得分:0)
将您的代码放在synchronized
块中的run方法中。 synchronized将确保一次只执行一个代码的一个线程。
run(){
synchronized(this){
....your code.
}}
您也可以run()
同步。
答案 3 :(得分:0)
一个简单而有点天真的解决方案就是在trolls
集合上进行简单的同步。如果这样做,请确保在Animator线程中yield
为您的checkTrolls
函数提供处理和清理的机会。
答案 4 :(得分:0)
我认为问题可能是在'checkTrolls'中你试图修改你正在迭代的向量。