使用RenderThread和UpdateThread进行游戏的Java LinkedList迭代器和线程安全

时间:2014-03-28 18:20:29

标签: java android multithreading linked-list thread-safety

我在Android应用程序中有一个共享的Java LinkedList,它有2个Threads,一个渲染线程和一个更新线程。两个线程不断运行并继续迭代共享的LinkedList。有时,更新线程必须从LinkedList中删除对象。我如何对程序进行编码以保持多线程性能但允许这种情况发生。我一直从渲染线程接收到java.util.ConcurrentModificationException,因为我猜测在我尝试渲染时正在删除该对象。

请注意,我在代码中使用了迭代器......

public void run()
{
  if(Thread.currentThread() == renderThread)
  {
    while(true)
    {
      for(Iterator<GameObject> it = objects.iterator(); it.hasNext();)
      {
         it.next().render();
      }
    }
  }
  if(Thread.currentThread() == updateThread)
  {
    while(true)
    {
      for(Iterator<GameObject> it = objects.iterator(); it.hasNext();)
      {
         GameObject o = it.next();

         it.next().update();

         if(o.shouldBeRemoved())
             it.remove();
      }
    }
  }
}

一个可能的解决方案是捕获异常并忽略它,但我觉得这是骗子的出路,因为异常应该用于特殊情况,而不是流量。

1 个答案:

答案 0 :(得分:1)

更新主题中的modifying your list structurally,同时呈现主题已创建 Iterator ,并且很开心迭代你的对象。您因未处理同步问题而受到ConcurrentModificationException的惩罚。

尝试使用 synchronized block / method wait()/ notify()搜索任何示例。

UPD:好的,这是对代码的简单修改,不会引发异常。这不是List同步的一个很好的例子,你没有获得太多的性能(更新和渲染操作仍然在不同的线程中,但是按顺序执行),并且有一些事情需要考虑 - 如果任何其他线程试图修改你的List,你仍然会得到一个并发的例外。

在你的启动器类中定义两个线程:

private Thread t1, t2;

启动线程的代码(例如inside public static void main(..)):

final List<GameObject> list = initList();//some initialization
t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            myMultipurposeMethod(list);
        }
    });

 t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            myMultipurposeMethod(list);
        }
    });
 t1.start();
 t2.start();

现在是 GameObject 类的简化版。注意同步块:

class GameObject {

    private int id;
    private static int count = 0;
    private boolean shouldDelete = false;
    private Object monitor = new Object();//will be used to lock critical section

    public GameObject() {
        id = ++count;
    }


    public void update(Thread thread) {
        synchronized (monitor) {
            shouldDelete = Math.random() < 0.5;//just a simple randomization
            System.out.println(thread.getName() + " updates GameObject. should be removed =" + shouldBeRemoved());
        }
    }

    public boolean shouldBeRemoved() {
        synchronized (monitor) {
            return shouldDelete;
        }
    }

    public void render(Thread thread) {
        System.out.println(thread.getName() + " renders GameObject " + id);
    }
}

最后,你的多功能方法:

public void myMultipurposeMethod(List<GameObject> ls) {
    synchronized (ls) {
        if (Thread.currentThread().equals(t1)) {
            while (true) {                    
                for (Iterator<GameObject> i = ls.iterator(); i.hasNext(); ) {
                    i.next().render(Thread.currentThread());
                    ls.notify();
                }
                try {
                    ls.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } else if (Thread.currentThread().equals(t2)) {
            while (true) {
                for (Iterator<GameObject> i = ls.iterator(); i.hasNext(); ) {
                    GameObject o = i.next();
                    o.update(Thread.currentThread());
                    if (o.shouldBeRemoved()) {
                        i.remove();
                        System.out.println("game object with id=" + o.id + " marked as garbage and was removed");
                    }
                }
                ls.notify();

                try {
                    ls.wait();
                } catch (InterruptedException e) {
                    e.printStackTract();
                }
            }
        }
    }
}

如果您遵循前言中给出的要求,那将为您提供并行执行的幻觉,并防止您的异常发生。但是,为了获得真正的性能提升,您最好不要遵循对OP的评论中给出的@ isnot2bad建议。