我有一个包含以下(Java)代码的方法:
doSomeThings();
doSomeOtherThings();
doSomeThings()
创建一些线程,每个线程只运行一段有限的时间。问题是我不希望在doSomeOtherThings()
启动的所有线程完成之前调用doSomeThings()
。 (同样doSomeThings()
将调用可能启动新线程的方法等等。我不想在所有这些线程完成之前执行doSomeOtherThings()
。)
这是因为doSomeThings()
等myObject
会将null
设置为doSomeOtherThings()
,而myObject.myMethod()
会调用myObject
而我不希望null
那时候是{{1}}。
有没有一些标准的方法来做这种事情(在Java中)?
答案 0 :(得分: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
)等等。
答案 1 :(得分: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();
答案 2 :(得分:3)
您正在寻找执行者服务并使用期货:)
请参阅http://java.sun.com/docs/books/tutorial/essential/concurrency/exinter.html
所以基本上收集你提交给执行者服务的所有runnables的期货。循环所有期货并调用get()方法。这些将在完成相应的runnable时返回。
答案 3 :(得分:1)
您可以使用的另一个有用的更强大的Synchronization Barrier与CountdownLatch类似的功能是CyclicBarrier。它类似于CountdownLatch,您必须知道正在使用多少方(线程),但它允许您重复使用屏障,因为每次都会创建一个新的CountdownLatch实例。
我确实喜欢momania建议使用ExecutorService,收集期货并调用所有这些直到他们完成。
答案 4 :(得分:0)
另一个选择是睡眠主线程,如果其他线程已经完成,请经常检查它。但是,我更喜欢Dirk和Marcus Adams的答案 - 只是为了完整起见而把它扔出去。
答案 5 :(得分:0)
取决于你在这里尝试做什么。您主要关心的是能否动态确定由doSomeThings()
内部调用的连续方法产生的各种线程,然后能够等到它们完成后再调用{{1 }?或者可以知道在编译时生成的线程?在后一种情况下,有许多解决方案,但所有这些解决方案基本上都涉及在所有这些线程上调用doSomeOtherThings()
方法。
如果确实是前者,那么最好使用Thread.join()
及其ThreadGroup
方法。如果您已经将新线程正确添加到ThreadGroup,这将为您提供由doSomeThings()生成的所有线程的数组。然后,您可以遍历返回数组中的所有线程引用,并在调用enumerate()
之前在主线程上调用join()
。