简体   繁体   English

LinkedList之间的区别 <T> 清晰和新的LinkedList <T> 在多线程环境中

[英]Difference between LinkedList<T> clear and new LinkedList<T> in a multithreaded environment

Why would this code: 为什么这个代码:

public synchronized void update() {
        for(T event : eventQueue)
        {
            processEvent(event);
        }
        events = eventQueue;
        eventQueue = new LinkedList<T>();
}

run differently to this code: 以不同的方式运行此代码:

public synchronized void update() {
            for(T event : eventQueue)
            {
                processEvent(event);
            }
            events = eventQueue;
            eventQueue.clear();
}

The first version works perfectly fine, however the second does not. 第一个版本完美无缺,但第二个版本没有。 The eventQueue.clear(); eventQueue.clear(); causes the app not to receive any events and finely crashes with a Concurrent Exception . 导致应用程序不接收任何事件并使用Concurrent Exception精细崩溃。

My app has two threads. 我的应用有两个主题。 The UI thread and the GameLoop thread. UI线程和GameLoop线程。 The UI thread adds events to the eventQueue like so: UI线程将事件添加到eventQueue如下所示:

public synchronized void addEvent(T newEvent) {
            eventQueue.add(newEvent);
}

The GameLoop thread calls the update method to get a copy (called events ) of the eventQueue . 该GameLoop线程调用Update方法来获得副本(称为events中的) eventQueue

All the code can be viewed from this website: http://entropyinteractive.com/2011/02/game-engine-design-input/ 所有代码都可以从这个网站上查看: http//entropyinteractive.com/2011/02/game-engine-design-input/

This seems kinda mysterious to me, since I thought eventQueue = new LinkedList<T>(); 这对我来说似乎有点神秘,因为我认为eventQueue = new LinkedList<T>(); and eventQueue.clear(); eventQueue.clear(); would both result in an empty LinkedList ? 会导致一个空的LinkedList吗? I believe it has something todo with establishing a new reference (But why?!). 我相信它有一些建议新的参考(但为什么?!)。

Because in this code: 因为在这段代码中:

public LinkedList<T> getEvents()
{
    return events;
}

You're returning the original list, not a copy. 您将返回原始列表,而不是副本。 If you then clear() that list, you'll cause issues because you're removing things from the list (and more important, changing the size of the list) while the other thread is using it. 如果然后clear()该列表,则会导致问题,因为您正在从列表中删除内容(更重要的是,更改列表的大小),而另一个线程正在使用它。

Note that this function isn't synchronized , so you can't even safely return a copy from it, because the original list could change while you're copying it (changing a reference is atomic , so it's safe to do that in your update() method). 请注意,此函数未synchronized ,因此您甚至无法安全地从其中返回副本,因为原始列表可能会在您复制时更改(更改引用是原子的 ,因此在update()这样做是安全的update()方法)。

You could return a copy from a synchronized method, like this: 您可以从同步方法返回一个副本,如下所示:

public synchronized LinkedList<T> getEvents()
{
    return new LinkedList<T>(events);
}

But that introduces an unnecessary copy and lock. 但这会引入不必要的副本和锁定。 Whether that matters depends on if you care more about defensive coding or performance requirements. 这是否重要取决于您是否更关心防御性编码或性能要求。 I assume they're doing it this way for performance reasons. 我认为出于性能原因他们这样做了。

Here is your problem 这是你的问题

  events = eventQueue;
  eventQueue.clear()

Once you assign events = eventQueue you are escaping the reference of eventQueue to the public via 一旦你指定了events = eventQueue你就可以将events = eventQueue的引用eventQueue给public

public LinkedList<T> getEvents()
{
    return events;
}

One thread can be iterating over the getEvents() queue which actually is eventQueue and another thread can be invoking addEvent and since the synchronized in addEvent no longer matches with the iterator of getEvents() you will get the comodification. 一个线程可以迭代getEvents()队列,实际上是eventQueue ,另一个线程可以调用addEvent ,因为addEventsynchronized不再与getEvents()的迭代器匹配,你将获得编码。

My suggestion is if you really want to publish your events do it with a new collection. 我的建议是,如果你真的想要发布你的事件,请使用新的集合。

  events = new LinkedList<T>(eventQueue);
  eventQueue.clear()

如果你不保护eventQueue 所有用法,比如在getEvents()分发引用,你应该尝试ConcurrentLinkedList

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM