2011-06-06 17 views
2

可以说我有大量的工作线程正在处理中,还有一个主管线程等待它们全部完成。传统上我可以这样做:如何Thread.join()在一个不断变化的大小列表的所有元素?

for(Worker w:staff){ 
    w.start(); 
} 
for(Worker w:staff){ 
    w.join(); 
} 

..一切都会好的。然而在这种情况下,我的工作者列表(ArrayList员工)的大小是可变的,并且可能会在任意时间更改。我最好的知识告诉我,这样的事情应该工作:

synchronized(this){ 
    for(Worker w:staff){ 
     w.start(); 
    } 
} 
while(true){ //this loop will keep the supervisor running until all workers have stopped 
        //interrupts will occur when changes to the size of staff list occur 
    try{ 
     Iterator<Worker> it; 
     synchronized(this){ 
      it = staff.iterator(); 
     } 
     while(it.hasNext()){ 
      Worker w = it.next(); 
      w.join(); 
     } 
     return; 
    }catch(InterruptedException ie){continue;} 
} 

然而,这还导致conncurrentModificationException上线

Worker w = it.next(); 

...这对我来说似乎很奇怪,因为我认为,一旦你检索了它与列表本身分开的迭代器。我的下一个想法是克隆迭代器或员工列表,以便它与原始更改列表分开,但我认为我会先给你专家一个镜头。

+0

除非你正在编写一些并发框架,否则使用像* join()*这样的低级java特有的东西几乎没有任何意义。我有一个250 KLOC左右的代码库,这是一个多线程应用程序(在所有内核上进行数字处理并传播负载)的一个代码,我们正在使用像* join()*这样的低级事物,以及...... **零**时间。但是更高层次的构造,如* Java Concurrency in Practice *中详述的那些,我们一直在使用。它充满了'生产者'和'消费者',但* join()*不是一次。 – SyntaxT3rr0r 2011-06-06 21:45:47

+0

同意你不应该使用'join'。你的代码存在问题:你永远不会'开始'将新的线程添加到列表中。如果你在别的地方启动它们,知道它是很重要的,因为它也需要同步。 – toto2 2011-06-06 23:10:24

回答

4

如果对Iterator实例以外的基础集合进行任何更改,则Iterator实例将失效。

为什么不考虑使用ExecutorService来代替?使Worker执行Callable,然后使用服务的invokeAll()方法之一。

CyclicBarrierCountDownLatch是可用于构建类似功能的较低级别的工具。

+0

我认为这将是正确的做事方式。但是代码现在写入。这次我会重复一下这个列表。下次我会费心去学习更高级的并发原语。 – Andrew 2011-06-06 22:17:10

+0

@Andrew - 不要等到下一次。这次修复它,并减少继任者必须处理的技术债务。 – 2011-06-07 00:39:18

2

当您尝试在Iterator部分完成时尝试修改列表时,您会收到ConcurrentModificationException,但是在您的代码示例中没有代码从列表中添加或删除,因此问题在代码中的其他位置。

基本上,在使用Interator时不要删除或添加列表,如果必须删除,可以使用Iterator.remove()而不是List.remove()删除项目。

+0

正如问题所述:“我的工作人员名单的大小是可变的,并且可能在任意时间发生变化”,所以仅仅是避免更改列表不是一种选择。 – Andrew 2011-06-06 22:12:30

相关问题