在程序执行过程中,会启动许多线程。线程数量取决于用户定义的设置,但它们都使用不同的变量执行相同的方法。
在某些情况下,执行过程中需要清理,其中一部分是停止所有线程,我不希望它们立即停止,我只是设置一个他们检查的变量来终止它们。问题是它可以在线程停止前最多1/2秒。但是,我需要确保在清理可以继续之前所有线程都已停止。清理是从另一个线程执行的,所以从技术上讲,我需要这个线程来等待其他线程完成。
我想过几种方法,但它们似乎都过于复杂。我希望有一些方法可以等待一组线程完成。有这样的事吗?
感谢。
答案 0 :(得分:56)
只需逐个加入:
for (Thread thread : threads) {
thread.join();
}
(您需要对InterruptedException
执行某些操作,并且您可能希望在出现问题时提供超时,但这是基本想法......)
答案 1 :(得分:14)
如果您使用的是Java 1.5或更高版本,则可以尝试CyclicBarrier。您可以将清理操作作为其构造函数参数传递,并在需要清理时在所有线程上调用barrier.await()
。
答案 2 :(得分:8)
自己定义一种实用方法(
)public static waitFor(Collection<? extends Thread) c) throws InterruptedException {
for(Thread t : c) t.join();
}
或者你可能有一个数组
public static waitFor(Thread[] ts) throws InterruptedException {
waitFor(Arrays.asList(ts));
}
或者,您可以使用CyclicBarrier
库中的java.util.concurrent
来实现多个线程之间的任意集合点。
答案 3 :(得分:7)
您是否在Executor
中看到过java.util.concurrent
个班级?您可以通过ExecutorService
运行线程。它为您提供了一个可用于取消线程或等待它们完成的对象。
答案 4 :(得分:1)
如果你控制线程的创建(提交给ExecutorService),那么看起来你可以使用ExecutorCompletionService
请参阅ExecutorCompletionService? Why do need one if we have invokeAll?了解各种答案。
如果你不控制线程创建,这里有一种方法,允许你在“完成”时逐个加入线程(并知道哪一个完成,等等),受到红宝石的启发{{3 } .class。 基本上通过新建“监视线程”,当其他线程终止时,它会发出警报,你可以知道许多终止的“下一个”线程何时终止。
您可以使用以下内容:
JoinThreads join = new JoinThreads(threads);
for(int i = 0; i < threads.size(); i++) {
Thread justJoined = join.joinNextThread();
System.out.println("Done with a thread, just joined=" + justJoined);
}
来源:
public static class JoinThreads {
java.util.concurrent.LinkedBlockingQueue<Thread> doneThreads =
new LinkedBlockingQueue<Thread>();
public JoinThreads(List<Thread> threads) {
for(Thread t : threads) {
final Thread joinThis = t;
new Thread(new Runnable() {
@Override
public void run() {
try {
joinThis.join();
doneThreads.add(joinThis);
}
catch (InterruptedException e) {
// "should" never get here, since we control this thread and don't call interrupt on it
}
}
}).start();
}
}
Thread joinNextThread() throws InterruptedException {
return doneThreads.take();
}
}
这很好的部分是它适用于通用Java线程,无需修改,任何线程都可以连接。需要注意的是,它需要一些额外的线程创建。如果你没有多次调用joinNextThread(),并且没有“关闭”方法等,这个特殊的实现“会留下线程”。如果你想要创建一个更精美的版本,请在此处注释。你也可以使用相同类型的模式和“Futures”而不是Thread对象等。