您好我正试图像蛇游戏一样在玩家身后添加尾巴。但由于某种原因,这种情况不断延续我的游戏并将其从内存中运行。为什么会发生这种情况?如何解决这个问题?
我创建了这样的列表:
List<Snake> snake = new CopyOnWriteArrayList<Snake>();
这是我创建新对象并在forloop中删除它们的地方:
public void snake() {
snake.add(new Snake(ball.getX(), ball.getY()));
currentTime++;
for(Snake currentSnake: snake) {
if(currentSnake.creationDate < SnakeLength){
currentSnake.Update();
} else {
Gdx.app.log("SnakeLength" + SnakeLength, "CreationDate" + currentSnake.creationDate);
snake.remove(currentSnake);
}
}
}
这就是我的蛇类的样子:
public class Snake
{
float width = Gdx.graphics.getWidth();
float height = Gdx.graphics.getHeight();
float screenwidth = width/270;
float screenheight = height/480;
public float x;
public float y;
public int creationDate;
ShapeRenderer shapeRenderer;
SpriteBatch batch;
public boolean active = false;
public Snake(float x, float y) {
shapeRenderer = new ShapeRenderer();
batch = new SpriteBatch();
this.x = x;
this.y = y;
}
public void Update() {
batch.begin();
shapeRenderer.begin(ShapeType.Filled);
shapeRenderer.setColor(new Color(1, 1, 1, 0.2f));
shapeRenderer.circle(x + 8*screenwidth, y + 8*screenheight, 6*screenheight);
shapeRenderer.end();
batch.end();
creationDate++;
}
}
答案 0 :(得分:2)
如javadoc CopyOnWriteArrayList所述:
ArrayList的线程安全变体,其中所有可变操作(添加,设置等)都是通过制作基础数组的新副本来实现的。
因此,它的操作成本很高,而且这个类很好地设计用于具有较小修改率的并发读取。看起来不是你的情况。
如果您选择此类来解决有关在修改List时读取List的问题,请考虑使用针对该用法设计的具有ArrayList的Iterators:
synchronized(snake) { // Protect the snake list against concurrent access. Do it whenever you access the snake list
for(Iterator<Snake> it = snake.iterator();; it.hasNext()) {
Snake currentSnake = it.next();
if(currentSnake.creationDate < SnakeLength) {
currentSnake.Update();
} else {
Gdx.app.log("SnakeLength" + SnakeLength, "CreationDate" + currentSnake.creationDate);
it.remove();
}
}
}
请注意,ArrayList不受并发访问保护。如果多个线程能够读取和写入列表,则必须使用同步块保护它。
但是阅读你的代码我觉得使用PriorityQueue的设计似乎更合适。
答案 1 :(得分:1)
我基本上认为你得到java.util.ConcurrentModificationException
例外,因为你试图删除元素(Snakes
),同时迭代你的List
@Dragondraikk提到。
这不是使用CopyOnWriteArrayList
的好理由,因为您可以在enter link description here中阅读,其中它解释了CopyOnWriteArrayList
的有用性。基本上CopyOnWriteArrayList
在
你最需要迭代ArrayList并且不要经常修改它
你不是。
为什么不修改检索到元素后的列表。如果您对此行为不满意,即您没有恒定数量的元素(我猜您不会)尝试在单独的循环中更新它们而不是删除/添加它们。
答案 2 :(得分:1)
在迭代时,您无法从列表中删除项目。在更新其余部分之前,您需要删除需要删除的蛇。
我建议:
snakes.removeIf(snake -> snake.createDate > snakeLength);
snakes.stream().forEach(Snake::Update);
答案 3 :(得分:1)
回答OP的问题:
你正在使用OOM,因为你使用的是CopyOnWriteArrayList
,我引用official docs是
ArrayList的线程安全变体,其中所有变异操作(添加,设置等)都由制作基础数组的新副本来实现。 (强调补充)