多线程环境中LinkedList <t> clear和new LinkedList <t>之间的区别</t> </t>

时间:2013-03-28 17:28:49

标签: java multithreading

为什么会这样的代码:

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?我相信它有一些建议新的参考(但为什么?!)。

3 个答案:

答案 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