2

我正在写一个小游戏,它在屏幕上移动了许多圆圈。
我在两个线程中管理圆圈,如下所示:

public void run() {
    int stepCount = 0;
    int dx;
    int dy;
    while (m_threadTrap){
        dx = 0;
        dy = 0;

        synchronized (m_circles) {
            for (Iterator<Circle> it = m_circles.iterator(); it.hasNext();){
                Circle c = it.next(); //Exception thrown here.
                if (c.getDirX() != 0)
                    if (stepCount % c.getDirX() == 0){
                        dx = 1;
                    }
                if (c.getDirY() != 0)
                    if (stepCount % c.getDirY() == 0){
                        dy = 1;                 
                    }

                c.move(dx, dy); 
            }
        }
        if (stepCount == 150000){
            stepCount = 0;
        }
        stepCount++;
    }
}

m_circles 在圆的 ArrayList 中。

以及以下线程:

public void run() {
    while (m_threadTrap){
        int topPosition;
        int bottomPosition;
        int leftPosition;
        int rightPosition;
        ArrayList<Circle> removedCircles = new ArrayList<Circle>();
        synchronized (m_circles.getCircles()) {
            for (Iterator<Circle> it = m_circles.getCircles().iterator(); it.hasNext();){
                Circle c = it.next();

                // Some calculation to evaluate which circles should be removed
                    removedCircles.add(c);
                }
            }
        }
        try{
            Thread.sleep(25);
        }
        catch (Exception e) { }

        m_circles.getCircles().removeAll(removedCircles);

        if (m_circles.getCircles().size() < 30)
            m_circles.addNewCircle();

        repaint(); 
    }
}

我的问题是我在该行得到 ConcurrentModificationException

Circle c = it.next();

在第一个线程中。起初,我尝试使用 foreach 循环遍历 ArrayList,这给了我同样的异常。
在对此异常进行了一些研究后,我看到了两个解决方案:
1. 将访问集合的部分放在同步块中。
2.使用集合的Iterator对象。
他们都没有为我解决这个问题。

4

2 回答 2

1

为了使synchronized() {}块有效,对受保护对象的所有访问都必须包装在同步块中。您可能忘记包装一些访问权限。

另一个“陷阱”是 ConcurrentModificationException 也可能意味着它在同一个线程中被同时修改。例如,如果您在遍历集合时从集合中删除一个元素,您可能会收到此异常。(作为一个例外,您可以通过迭代器本身安全地删除元素)

于 2012-02-10T08:34:29.557 回答
1

ConcurrentModificationException 意味着您正在迭代一个集合,并且在迭代时,某人(当前线程或另一个线程)修改了底层集合而不使用Iterator.remove(). 每当您在 Iterator 上调用操作时,它都会检查基础集合是否未更改。使用 foreach 不会改变任何事情,因为它使用 Iterator 来执行循环。

您的解决方案是:

  1. 创建一个新集合:

    for (Circle c: new ArrayList(m_circles.getCircles()).iterator()) { // 一些计算来评估哪些圆圈应该被移除 removedCircles.add(c); }

  2. 或在修改或访问集合时同步同一对象上的两个线程(您在不同的对象上同步,因此它不做任何事情)

于 2012-02-10T08:40:16.333 回答