我的游戏更新循环经常迭代ArrayList
,我还有一个KeyListener
,当按下按钮时,它会向Object
添加ArrayList
,似乎导致并发修改异常。
经过大量的调查后,我决定最好尝试(我是Java的新手)找出一种方法将关键事件合并到主线程中。鉴于这种情况,我该怎么做,或者有没有办法做到这一点,我没有看到?感谢。
PS:我可以研究更高级的方法,但我宁愿尝试保持相当单线程,并将关键事件传递给主线程。
答案 0 :(得分:2)
我假设您正在运行一个事件循环,您希望将事件添加到正文的末尾。如果是这样,您可能希望使用java.util.Queue实现,例如LinkedList并执行
while((event=queue.poll()) != null) {
/* process event */
queue.add(keyEvent);
}
答案 1 :(得分:2)
解决方案1:
请记住,在迭代过程中,您的密钥监听器将被阻止(这也意味着您的迭代器在旧数据上运行,与解决方案2一样)。
如果使用ArrayList,请执行以下操作:
List list = Collections.synchronizedList(new ArrayList());
并在每个地方使用此list
对象。你必须导入
import java.util.Collections;
我同意@msandiford添加如何迭代......
while(some_condition) {
do something
synchronized(list) {
Iterator i = list.iterator();
while (i.hasNext())
do_something_with(i.next());
}
do something else
}
如果你有迭代的外部循环,这是快速解决方案。因此,您暂时不在synchronized
块中,以便KeyListener
可以添加到数组列表中。
解决方案2:
如果你想使用COW,请注意每当发生添加/更新操作时,它都会复制下面的集合,你的迭代器将不会看到更改。但是不会阻止关键监听器(但此时将在下面创建一个新副本)。
import java.util.concurrent.CopyOnWriteArrayList;
List list = new CopyOnWriteArrayList<your_object_type>();
对于迭代:
while(some_condition) {
do something
Iterator i = list.iterator();
while (i.hasNext())
do_something_with(i.next());
do something else
}
解决方案3:
这将是轻微的设计变更。它类似于解决方案2,但只有在您只进行添加操作时才有意义。所以你可以做的是创建另一个临时List
并在Keylistener
中添加到此列表中。一旦你的迭代通过make synchronized
阻止并将所有对象从temp List
移动到List
,你就会用于迭代。这不会阻止您的KeyListener,但迭代器将看到解决方案2中的旧数据。与解决方案2相比,它可能具有更好的性能。
因此,选择对您的设计有意义的解决方案。
价:
答案 2 :(得分:1)
对于事件队列,我通常使用ConcurrentLinkedQueue ,因为队列非常适合此模型(比List / ArrayList好得多)。
队列更容易以这种线程方式使用,因为在列表意义上没有“迭代”队列:只需按下一个项目,抓取一个项目。这两个操作都可以是原子操作(并且相对容易同步)。
我更倾向于使用假设/要求来处理此模型,一旦从队列中消耗了一个对象,它就可以被该线程视为“拥有”(将对象置于其中的线程应该放弃该对象,直到它获得对象为止) ,通过另一个队列,如果有的话。)
的ConcurrentLinkedQueue:
基于链接节点的无界线程安全队列。这个队列命令元素FIFO(先进先出)...当许多线程共享对公共集合的访问权限时,ConcurrentLinkedQueue是一个合适的选择[但对于2来说“很好”... ...
CopyOnWriteArrayList是另一种可以使用的结构,尽管它更像是一种“通用”结构。我不确定哪个“更快”,但考虑到我从未遇到过ConcurrentLinkedQueue的问题,这是我的第一个主要选择,原因如上所述。还有一些不同的并发安全队列实现,包括绑定队列,也可以在concurrent包中找到。
当然,要保持“旧学校”,只需在同一个对象上同步 ,1)修改(或迭代)EDT中的集合(无论何时发生)2)迭代集合在游戏线程中。这将使操作互斥并防止此异常。一个“缺点”是,这可能会阻止UI线程,具体取决于循环保持锁定的时间。这种方法也可以用于普通的非同步队列。
快乐的编码。