2010-04-05 64 views
4

我已经包含下面的(Java)的代码的方法:等待上的螺纹

doSomeThings(); 
doSomeOtherThings(); 

doSomeThings()创建某些线程,其中的每一个将仅用于有限的时间量运行。问题是我不希望doSomeOtherThings()被调用,直到doSomeThings()启动的所有线程都完成。 (也doSomeThings()将调用可能会推出新的线程方法等等。我不想执行doSomeOtherThings()直到所有这些线程完成。)

这是因为doSomeThings(),除其他事项外将设置myObjectnull,而doSomeOtherThings()调用myObject.myMethod(),我不想当时myObjectnull

有没有一些标准的方法来做这种事情(在Java中)?

回答

10

你可能想看看在java.util.concurrent包。特别是,你可以考虑使用CountDownLatch

package de.grimm.game.ui; 

import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class Main { 

public static void main(String[] args) 
throws Exception { 

    final ExecutorService executor = Executors.newFixedThreadPool(5); 
    final CountDownLatch latch = new CountDownLatch(3); 

    for(int k = 0; k < 3; ++k) { 

     executor.submit(new Runnable() { 
      public void run() { 
       // ... lengthy computation... 
       latch.countDown(); 
      } 
     }); 
    } 

    latch.await(); 

    // ... reached only after all threads spawned have 
    // finished and acknowledged so by counting down the 
    // latch. 

    System.out.println("Done"); 
} 
} 

显然,这种技术只会工作,如果你知道分叉线程的数量事先,因为你需要初始化与数字锁。

另一种方法是使用条件变量,例如:

boolean done = false; 

void functionRunInThreadA() { 

    synchronized(commonLock) { 

     while(!done) commonLock.wait(); 
    } 

    // Here it is safe to set the variable to null 
} 

void functionRunInThreadB() { 

    // Do something... 

    synchronized(commonLock) { 
     done = true; 
     commonLock.notifyAll(); 
    } 
} 

您可能需要添加异常处理(InteruptedException)和一些这样的。

+0

(+1)'CountdownLatch'非常方便 – skaffman 2010-04-05 21:15:53

6

看看Thread.join()方法。

我不清楚你的确切实现,但它似乎像doSomeThings()应该在返回之前等待子线程。

在doSomeThings()方法内部,通过调用Thread.join()方法等待线程。

当您创建一个线程并调用该线程的join()方法时,调用线程将等待,直到该线程对象死亡。

例子:

// Create an instance of my custom thread class 
MyThread myThread = new MyThread(); 
// Tell the custom thread object to run 
myThread.start(); 
// Wait for the custom thread object to finish 
myThread.join(); 
+0

-1调用myThread.run不会启动新的线程。 myThread.join()在myThread.run()完成时被调用的事实仅仅是因为程序顺序而不是任何异步原因 – 2010-04-05 21:05:49

+0

在该示例中应该是'myThread.start()'。 – 2010-04-05 21:20:00

+0

@唐纳,哎呀。谢谢。我更新了答案。 @约翰,对不起,这是一个错字。我习惯于从Runnable继承而不是Thread。 – 2010-04-06 13:35:55

0

另一个选择是睡觉你的主线程,并且每隔一段时间检查一次,如果其他线程已经完成。不过,我更喜欢德克和马库斯亚当斯的答案 - 只是为了完整而抛弃了这一点。

1

另一个更有用的更强大Synchronization Barrier你可以使用那个会做类似功能的CountdownLatch是CyclicBarrier。它的作用类似于CountdownLatch,您必须知道正在使用多少个参与者(线程),但它允许您重复使用障碍,以便每次创建一个CountdownLatch的新实例。

我的确喜欢momania建议的使用ExecutorService,收集期货并在它们完成之前调用get。

0

取决于你在这里做什么。你主要关心的是能否动态确定由连续方法产生的各种线程,这些线程在doSomeThings()之内被调用,然后能够在调用doSomeOtherThings()之前等到他们完成之前完成?或者有可能知道在编译时产生的线程?在后一种情况下有很多解决方案,但基本上都涉及从创建它们的所有这些线程调用Thread.join()方法。

如果它确实是前者,那么你最好使用ThreadGroup及其enumerate() 方法。这给了你一个由doSomeThings()产生的所有线程的数组,如果你已经正确地向ThreadGroup添加了新线程。然后,您可以循环返回返回数组中的所有线程引用,并在致电doSomeOtherThings()之前在主线程上调用join()