简体   繁体   English

在一个类中遍历arraylist,而在另一类中添加元素

[英]Iterating through arraylist in one class, while adding an element in other class

i'm getting a concurrentmodification exception, the problem is that i'm iterating through an arrayList and drawing and updating the sprites in the arraylist, while adding new sprites in another java class. 我收到并发修改异常,问题是我要遍历arrayList并绘制和更新arraylist中的精灵,同时在另一个java类中添加新的精灵。

public abstract class Scene
{
    ArrayList<UIElement> uiElements = new ArrayList<>();
    ArrayList<GameObject> sprites = new ArrayList<>();

    public ArrayList<GameObject> getSprites()
    {
        return sprites;
    }

    public ArrayList<UIElement> getUiElements()
    {
        return uiElements;
    }

    public abstract void load();

    public abstract void unload();

    public void update()
    {
        sprites.forEach(GameObject::update);
        uiElements.forEach(UIElement::update);
    }

    public void draw(Graphics2D g2)
    {
        sprites.forEach(e -> e.draw(g2));

        uiElements.forEach(e -> e.draw(g2));
    }

}

so these are the iterating methods in the java class named Scene.java 所以这些是名为Scene.java的Java类中的迭代方法

    public void onButtonsEvent(WiimoteButtonsEvent wiimoteButtonsEvent)
    {
//      shoot firebolt when button b is held
        if(  wiimoteButtonsEvent.isButtonBHeld())
        {
            if(updateIndexTwo % UPDATE_SPEED == 0)
            {
                Vector2D fireboltVector = new Vector2D(vector.getX()+SPRITE_WIDTH/2, vector.getY(), crossHair.getX() + CH_SIZE/2, crossHair.getY() + CH_SIZE/2);
                Firebolt firebolt = new Firebolt(fireboltVector, damage, color, scene);
                scene.getSprites().add(firebolt);
                updateIndexTwo = 0;
            }
            updateIndexTwo++;
        }
    }

this is the code where the Firebolt(sprite) will be added to the sprites arraylist in Scene 这是将Firebolt(sprite)添加到Scene中的sprites arraylist中的代码

i'm getting a concurrentmodification exception, the problem is that i'm iterating through an arrayList and drawing and updating the sprites in the arraylist, while adding new sprites in another java class. 我收到并发修改异常,问题是我要遍历arrayList并绘制和更新arraylist中的精灵,同时在另一个java类中添加新的精灵。

The basic solution is fairly simple: don't do that. 基本解决方案非常简单:请勿这样做。 It is an intentional design feature that if an ArrayList is structurally modified, then any iterators over that list that were obtained prior to the modification are invalidated; 一个有意设计的功能是,如果对ArrayList进行了结构修改,则在修改之前在该列表上获得的所有迭代器都将无效; further use of them causes ConcurrentModificationException to be thrown. 进一步使用它们会引发ConcurrentModificationException This happens whether you're using Iterator s directly, using an enhanced for loop, or using forEach() . 无论您是直接使用Iterator ,使用增强的for循环还是使用forEach() ,都会发生这种情况。 The other basic collections classes ( LinkedList , HashSet , etc.) all work the same way. 其他基本集合类( LinkedListHashSet等)都以相同的方式工作。

If indeed you must accommodate the collection being modified without breaking an ongoing iteration over it, then you need a collection class that accomodates such activity. 如果确实必须在不中断正在进行的迭代的情况下容纳要修改的集合,那么您需要一个容纳此类活动的集合类。 For example, you could consider ConcurrentLinkedDeque , or one of the other collections from java.util.concurrent . 例如,您可以考虑使用ConcurrentLinkedDequejava.util.concurrent中的其他集合之一。 It is possible to write your own, but it's tricky, and why do that when there are existing classes in the standard library that will serve? 可以编写自己的代码,但这很棘手,为什么在标准库中已有可以使用的类的情况下这样做呢?

Note also that although a solution can be found in java.util.concurrent, the problem does not depend on multiple threads being involved. 还要注意,尽管可以在java.util.concurrent中找到解决方案,但问题并不取决于所涉及的多个线程。 In fact, if you do have multiple threads then using one of the concurrent collections serves a dual purpose: it also ensures consistent operations on the collection without need of external synchronization. 实际上,如果您确实有多个线程,那么使用并发集合之一可以达到双重目的:它还可以确保对集合进行一致的操作而无需外部同步。 If by any chance you were previously accessing the list from multiple threads without proper synchronization then getting the CME was a lucky break -- you might instead have just gotten silent malfunction. 如果您有机会在没有适当同步的情况下从多个线程访问列表,那么获得CME是一个幸运的休息-您可能只是陷入了静默故障。

Look at an existing thread safe class such as ArrayBlockingQueue. 查看现有的线程安全类,例如ArrayBlockingQueue。 You can wrap your ArrayList in synchronization code but it's easier to use a data structure that already does what you want. 您可以将ArrayList包装在同步代码中,但是使用已经可以完成所需功能的数据结构会更容易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM