简体   繁体   English

我如何遍历可能由另一个线程添加到的列表

[英]How do I iterate over a list that could be added to by another thread

I have a list that I iterate over and perform some actions on. 我有一个列表,可以对其进行迭代并对其执行一些操作。 One of the actions that can be performed can result in work being passed off to another thread, which may add more elements to my list while I'm still iterating over it in the first thread. 可以执行的操作之一可能导致工作传递给另一个线程,这可能会在我仍在第一个线程中对其进行迭代时将更多元素添加到列表中。

Is there a way for me to iterate over the list in such a way that the iterator includes the additions from the other thread? 有没有办法让我迭代列表,使迭代器包括来自另一个线程的添加项?

Here's some pseudo Java 这是一些伪Java

Class1{

   List multiThreadList = getMyList(); //points to list in Class2
   for(Element element:multiThreadList)
      //perform some actions, these actions may results in another thread being called
      //which will cause addToMyList() to be called while I'm still iterating over it
      //I want to keep iterating if an element gets added on the other thread
}
Class2{
   List originalList = new ArrayList();

   public getMyList()
     return originalList;

   void addToMyList(Element element)
     originalList.add(element);
}

Are you sure List is the kind of collection you need? 您确定List是您需要的那种收藏吗?

I would use BlockingQueue, and remove elements from BlockingQueue in one Thread, and add in another. 我将使用BlockingQueue,并在一个线程中从BlockingQueue中删除元素,然后添加另一个。 This way you would not need any additional concurrency control. 这样,您将不需要任何其他的并发控制。

BlockingQueue<String> bounded   = new LinkedBlockingQueue<String>();

bounded.put("Value");

String value = bounded.take();

Your pseudo code becomes 您的伪代码成为

Class1{

   BlockingQueue queue = getMyList();
   Object element = queue.poll(0, TimeUnit.SECONDS);
   while(element != null) {
      //perform some actions, these actions may results in another thread being called
      //which will cause addToMyList() to be called while I'm still iterating over it
      //I want to keep iterating if an element gets added on the other thread  
      element = queue.poll(0, TimeUnit.SECONDS);
   }
}
Class2{
   BlockingQueue originalList = new LinkedBlockingQueue();

   public BlockingQueue getMyList()
     return originalList;

   void addToMyList(Element element)
     originalList.put(element);
}

But one thing, you need to understand, that this task in current form would give you inconsistent results. 但是有一件事,您需要了解,当前形式的此任务会给您带来不一致的结果。 Since you don't control another Thread, your iterator might finish, before new element was added, and you will miss it, while iterating, depending on the state of the system you can miss from zero to all new elements. 由于您不控制另一个线程,因此迭代器可能会在添加新元素之前完成,并且在迭代时会丢失它,具体取决于系统状态,您可能会错过从零到所有新元素的情况。 So you either need to join all created Threads, before you finish iterating, or change the approach. 因此,您需要在完成迭代之前加入所有创建的线程,或者更改方法。

You would have to use some type of concurrency control mechanism, such as a Mutex lock, a semaphore, or a monitor. 您将必须使用某种类型的并发控制机制,例如互斥锁,信号灯或监视器。 These create a 'critical section' of your code which would allow only one thread to access it at a time. 这些会创建代码的“关键部分”,一次仅允许一个线程对其进行访问。

Unfortunately, there is no solution to the problem without somehow locking the code and making a portion of it serial. 不幸的是,如果不以某种方式锁定代码并将其一部分串行化,就无法解决该问题。

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

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