2011-06-09 79 views
5

我有一个类,它产生了一堆线程,必须等到所有衍生线程完成。 (我需要计算所有线程完成的时间)。Java:Multithreading -Wait/notifyAll问题

MainClass产生所有的线程,然后检查是否所有线程都完成,然后它可以调用自己完成。

此逻辑是否有效。如果是这样,是否有更好的方法来做到这一点?如果不是,我想更好地理解这种情况。

class MainClass{ 
    private boolean isCompleted; 
    ... 
    for(task : tasks){ 
     threadpool.execute(task); 
    } 

    for(task : tasks){ 
     if(!task.isCompleted()){ 
      task.wait() 
     } 
    } 

    isCompleted = true; 
} 


class Task{ 
    public void run(){ 
     .... 
     .... 
     synchronized(this){ 
      task.completed = true; 
      notifyAll(); 
     } 
    } 
} 
+1

我认为你的代码不起作用,因为你忘记了'wait()'附近的'synchronized'块。查看我的答案以获得更好(更快)的解决方案。 – 2011-06-09 17:30:06

+0

太棒了!正是我在找什么。我需要至少5分钟。在我可以关闭它之前。 :) – 2011-06-09 17:31:32

回答

11

notifyAll()是比较慢。更好的方法是使用CountDownLatch

import java.util.concurrent.CountDownLatch; 

int n = 10; 
CountDownLatch doneSignal = new CountDownLatch(n); 
// ... start threads ... 
doneSignal.await(); 

// and within each thread: 
doWork(); 
doneSignal.countDown(); 
+1

+1,但你没有解释为什么'CountDownLatch'会是一个更好的选择,除了任意(并且隐含地)说它比等待通知方案更快。 – mre 2011-06-09 17:30:13

+1

我确实有一个问题。如果倒计数从未达到0.线程是否挂起? – 2011-06-09 17:39:19

+0

@Vanchinathan Chandrasekaran是的。 – 2011-06-09 17:47:50

4

有没有必要等待/通知在这种情况下。您可以循环访问线索并致电join()。如果线程已经完成,MainClass线程将等待下一个线程。

您可能也想看看java.util.concurrent包中的更高级别的实用程序。

+0

+1,用于提及简单的解决方案(即'Thread.join()')和引用'java.util.concurrent'包作为更好的选择。 – mre 2011-06-09 17:34:12

4

所有这些都可以通过java.util.concurrent.ExecutorService完成。

class MainClass { 
    ... 
    ExecutorService executor = Executors.newCachedThreadPool(); 
    List<Callable> tasks = ...; // prepare your tasks 

    // this invokes all tasks in parallel and waits until all are done 
    executor.invokeAll(tasks); 
    ... 
} 

就是这样。

+0

我刚刚尝试过,程序在'invokeAll'后运行了一阵子。我发现你必须调用'executor.shutdown();'释放所有的线程和程序可以立即结束。 – 2013-12-07 22:08:03