为什么会这样的代码:
public synchronized void update() {
for(T event : eventQueue)
{
processEvent(event);
}
events = eventQueue;
eventQueue = new LinkedList<T>();
}
对此代码的运行方式不同:
public synchronized void update() {
for(T event : eventQueue)
{
processEvent(event);
}
events = eventQueue;
eventQueue.clear();
}
第一个版本完全正常,但第二个版本没有。 eventQueue.clear();
会导致应用无法接收任何事件,并使用Concurrent Exception
进行严重崩溃。
我的应用有两个主题。 UI线程和GameLoop线程。 UI线程将事件添加到eventQueue
,如下所示:
public synchronized void addEvent(T newEvent) {
eventQueue.add(newEvent);
}
GameLoop线程调用update方法获取events
的副本(名为eventQueue
)。
可以从这个网站查看所有代码:http://entropyinteractive.com/2011/02/game-engine-design-input/
这对我来说似乎有点神秘,因为我认为eventQueue = new LinkedList<T>();
和eventQueue.clear();
会导致空LinkedList
?我相信它有一些建议新的参考(但为什么?!)。
答案 0 :(得分:3)
因为在此代码中:
public LinkedList<T> getEvents()
{
return events;
}
您将返回原始列表,而不是副本。如果您然后clear()
该列表,则会导致问题,因为您正在从列表中删除内容(更重要的是,更改列表的大小),而另一个线程正在使用它。
请注意,此功能不是synchronized
,因此您甚至无法安全地从中返回副本,因为原始列表可能会在您复制时更改(更改引用为atomic },所以在你的update()
方法中这样做是安全的。
您可以从同步方法返回副本,如下所示:
public synchronized LinkedList<T> getEvents()
{
return new LinkedList<T>(events);
}
但是这引入了不必要的副本和锁定。这是否重要取决于您是否更关心defensive coding或性能要求。我认为出于性能原因,他们是这样做的。
答案 1 :(得分:0)
这是你的问题
events = eventQueue;
eventQueue.clear()
在您指定events = eventQueue
后,您正在通过
eventQueue
的引用
public LinkedList<T> getEvents()
{
return events;
}
一个线程可以在getEvents()
队列上进行迭代,实际上是eventQueue
,另一个线程可以调用addEvent
,因为addEvent中的synchronized
不再与getEvents()
的迭代器,你将得到编纂。
我的建议是,如果您真的想发布您的活动,请使用新的收藏品。
events = new LinkedList<T>(eventQueue);
eventQueue.clear()
答案 2 :(得分:0)
如果您不保护eventQueue
的所有用途,例如在getEvents()
中分发参考,则应尝试ConcurrentLinkedList
。