在Java中等待多个线程完成
在我的程序执行过程中,启动了许多线程。线程的数量因用户定义的设置而异,但它们都使用不同的变量执行相同的方法 在某些情况下,在执行过程中需要进行清理,其中一部分是停止所有线程,但我不希望它们立即停止,我只是设置了一个变量,让它们检查以终止它们。问题是,在线程停止之前,它可能长达1/2秒。但是,我需要确保所有线程都已停止,然后才能继续清理。清理是从另一个线程执行的,所以技术上我需要这个线程等待其他线程完成 我已经想到了几种方法,但它们似乎都过于复杂。我希望有一些方法可以等待一组线程完成。有这样的事吗在Java中等待多个线程完成,java,multithreading,synchronization,Java,Multithreading,Synchronization,在我的程序执行过程中,启动了许多线程。线程的数量因用户定义的设置而异,但它们都使用不同的变量执行相同的方法 在某些情况下,在执行过程中需要进行清理,其中一部分是停止所有线程,但我不希望它们立即停止,我只是设置了一个变量,让它们检查以终止它们。问题是,在线程停止之前,它可能长达1/2秒。但是,我需要确保所有线程都已停止,然后才能继续清理。清理是从另一个线程执行的,所以技术上我需要这个线程等待其他线程完成 我已经想到了几种方法,但它们似乎都过于复杂。我希望有一些方法可以等待一组线程完成。有这样的事吗
谢谢。一个接一个地加入他们吧:
for (Thread thread : threads) {
thread.join();
}
(您需要对InterruptedException执行一些操作,并且您可能希望在出现问题时提供一个超时,但这是基本想法…自己定义一个实用方法:
public static waitFor(Collection<? extends Thread) c) throws InterruptedException {
for(Thread t : c) t.join();
}
或者,您可以在
java.util.concurrent
库中使用CyclicBarrier
来实现多个线程之间的任意集合点。如果您使用的是java 1.5或更高版本,您可以尝试。您可以将清理操作作为其构造函数参数传递,当需要清理时,只需在所有线程上调用barrier.await()
。您是否在java.util.concurrent
中看到了Executor
类?您可以通过执行器服务运行线程。它为您提供了一个对象,您可以使用它来取消线程或等待线程完成。如果您控制线程的创建(提交给ExecutorService),那么您似乎可以使用ExecutorCompletionService
请参阅此处的各种答案
如果您不控制线程的创建,这里有一种方法可以让您“在线程完成时一个接一个地”加入线程(并知道哪个线程先完成,等等),这是受ruby类启发的。
基本上,通过更新“监视线程”,当其他线程终止时发出警报,您可以知道多个线程中的“下一个”线程何时终止
你可以这样使用它:
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);
}
JoinThreads join=新的JoinThreads(线程);
对于(int i=0;i
资料来源:
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();
}
}
公共静态类JoinThreads{
java.util.concurrent.LinkedBlockingQueue doneThreads=
新建LinkedBlockingQueue();
公共连接线程(列出线程){
用于(螺纹t:螺纹){
最终螺纹接头this=t;
新线程(newrunnable()){
@凌驾
公开募捐{
试一试{
joinThis.join();
添加(joinThis);
}
捕捉(中断异常e){
//“应该”永远不会到达这里,因为我们控制这个线程,不调用它的中断
}
}
}).start();
}
}
线程joinNextThread()抛出InterruptedException{
返回doneThreads.take();
}
}
这其中很好的一点是,它可以与通用Java线程一起工作,无需修改,任何线程都可以连接。需要注意的是,它需要一些额外的线程创建。此外,如果调用joinNextThread()的次数不完整,并且没有“close”方法等,则此特定实现会“留下线程”。如果希望创建更完善的版本,请在此处进行注释。您也可以将这种类型的模式与“Futures”一起使用,而不是线程对象等等。谢谢,这似乎可以满足我的要求,但当我看到这一点时,已经写好了Jon的答案。如果您只做一次,另一种方法是使用CountdownLatch。@Jon Skeet,我有一个疑问。line
thread.join()
将使当前进程等待线程线程运行,对吗?然后这里将发生的是,主进程将到达第二行,并等待线程完成其工作,然后它将进入循环中的下一个线程,所以实际上main将等待第一个子线程运行,然后它将为下一个线程执行线程.join()
,我说的对吗?@Pratik:它将阻止当前线程(不是进程),直到线程
完成(不是启动)。我们的期望是,在我的答案中的代码执行之前,所有线程都已经在运行了。。。它只是等待它们中的每一个都完成。@Jon skeet,请澄清一下,我知道如果一个线程main正在调用thread.join(),那么主线程将暂停,当threadthread
完成时,main将恢复。我说得对吗?现在,假设变量threads
中有3个线程,那么for
循环将执行3次,第1个thread
main的第1次将执行。join()
然后系统将暂停它,并在第一个线程完成后恢复。然后,只有它才能再次进入下一个(第二个)线程元素的循环。我说得对吗?另一点需要注意的是,当主线程移动到加入第二个线程时,它可能已经完成了。在这种情况下,将立即返回。因此,主线程将继续连接第三个线程。@ThomasAhle:是的,它会-通常立即退出是正确的做法;其他时候你可能会想用不同的方式来处理。令人惊讶的是,这确实是最好的方法。它允许您使用多个线程,但保持有限的线程数,可能是基于设备上的内核数。
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();
}
}