【问题标题】:How do I iterate over a list that could be added to by another thread如何迭代可以由另一个线程添加到的列表
【发布时间】:2014-09-18 02:12:08
【问题描述】:

我有一个列表,我会对其进行迭代并执行一些操作。可以执行的操作之一可能会导致工作被传递给另一个线程,这可能会在我仍在第一个线程中对其进行迭代时将更多元素添加到我的列表中。

有没有办法让我以迭代器包含来自其他线程的添加的方式遍历列表?

这是一些伪 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);
}

【问题讨论】:

  • 你能提供一些代码吗?
  • 您可以将列表转换为数组,您可以在列表周围放置共享锁。您可以使用同步列表
  • 这真的取决于你的具体要求,你可能不用锁就能逃脱,你可能需要锁。迭代过程中是否可以从列表中删除,紧随其后,addToMyList 是否需要很长时间才能将内容添加到列表中?
  • @MateuszDymczyk 在迭代期间没有删除列表,只有添加,addToMyList 可能需要很长时间,这就是我不想等待任意时间单位的原因

标签: java multithreading concurrency


【解决方案1】:

你确定 List 是你需要的那种集合吗?

我会使用 BlockingQueue,并在一个线程中从 BlockingQueue 中删除元素,然后在另一个线程中添加。这样您就不需要任何额外的并发控制。

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

bounded.put("Value");

String value = bounded.take();

你的伪代码变成了

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);
}

但有一件事,您需要了解,当前形式的这项任务会给您带来不一致的结果。由于您不控制另一个线程,因此您的迭代器可能会在添加新元素之前完成,并且您会在迭代时错过它,这取决于系统的状态,您可能会错过从零到所有新元素。因此,您要么需要在完成迭代之前加入所有创建的线程,要么更改方法。

【讨论】:

  • +1。请注意,“阻塞”是指take。您的消费者将等到要处理的元素可用(无论如何这可能是您想要的)。 put 无需等待。
  • 我喜欢这个,告诉我(因为我是并发新手)这是使它异步的一个例子吗?
  • 它是异步的,因为你有两个(或更多)线程。一个放入东西,一个处理它。
  • 换句话说,这很容易演变成时间问题,是否有同步的方法,我想避免任意超时
  • 并非如此。事物按照放入队列的顺序进行处理。您不想在所有生产者完成之前关闭消费者。也许还可以查看 CompletionService 进行异步计算。
【解决方案2】:

您必须使用某种类型的并发控制机制,例如互斥锁、信号量或监视器。这些会创建代码的“关键部分”,一次只允许一个线程访问它。

不幸的是,如果不以某种方式锁定代码并使其一部分串行化,就无法解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2020-01-23
    • 1970-01-01
    相关资源
    最近更新 更多