我在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();
}
}
}
}
一个可能的解决方案是捕获异常并忽略它,但我觉得这是骗子的出路,因为异常应该用于特殊情况,而不是流量。
答案 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建议。