为什么这段代码:
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 线程调用更新方法来获取 events
的副本(称为 eventQueue
) .
所有代码都可以在这个网站查看:http://entropyinteractive.com/2011/02/game-engine-design-input/
这对我来说有点神秘,因为我认为 eventQueue = new LinkedList<T>();
和 eventQueue.clear();
都会导致空的 LinkedList
?我相信它与建立新引用有关(但为什么呢?!)。
最佳答案
因为在这段代码中:
public LinkedList<T> getEvents()
{
return events;
}
您返回的是原始列表,而不是副本。如果您随后 clear()
该列表,您将导致问题,因为您正在从列表中删除内容(更重要的是,更改列表的大小),而另一个线程正在使用它。
请注意,此函数不是同步
,因此您甚至无法安全地从中返回一个副本,因为原始列表可能会在您复制它时更改(更改引用为 atomic ,因此在您的 update()
方法中这样做是安全的。
您可以从同步方法返回一个副本,如下所示:
public synchronized LinkedList<T> getEvents()
{
return new LinkedList<T>(events);
}
但这引入了不必要的复制和锁定。这是否重要取决于您是否更关心 defensive coding 或性能要求。我假设他们出于性能原因这样做。
关于java - 多线程环境下 LinkedList<T> clear 和 new LinkedList<T> 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15688367/