简单地等待所有线程进程完成的方法是什么?例如,假设我有:
public class DoSomethingInAThread implements Runnable{
public static void main(String[] args) {
for (int n=0; n<1000; n++) {
Thread t = new Thread(new DoSomethingInAThread());
t.start();
}
// wait for all threads' run() methods to complete before continuing
}
public void run() {
// do something here
}
}
如何改变这一点,以便main()
方法在注释处暂停,直到所有线程的run()
方法都退出?谢谢!
答案 0 :(得分:153)
您将所有线程放在一个数组中,然后启动所有线程,然后进行循环
for(i = 0; i < threads.length; i++)
threads[i].join();
每个连接都将阻塞,直到相应的线程完成。线程可以以与加入它们不同的顺序完成,但这不是问题:当循环退出时,所有线程都完成。
答案 1 :(得分:37)
一种方法是创建List
Thread
,创建并启动每个线程,同时将其添加到列表中。一旦启动所有内容,循环回列表并在每个列表上调用join()
。线程完成执行的顺序并不重要,您需要知道的是,当第二个循环完成执行时,每个线程都将完成。
更好的方法是使用ExecutorService及其相关方法:
List<Callable> callables = ... // assemble list of Callables here
// Like Runnable but can return a value
ExecutorService execSvc = Executors.newCachedThreadPool();
List<Future<?>> results = execSvc.invokeAll(callables);
// Note: You may not care about the return values, in which case don't
// bother saving them
使用ExecutorService(以及来自Java 5 concurrency utilities的所有新东西)非常灵活,上面的例子几乎没有表面上的。
答案 2 :(得分:24)
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class DoSomethingInAThread implements Runnable
{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
//limit the number of actual threads
int poolSize = 10;
ExecutorService service = Executors.newFixedThreadPool(poolSize);
List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();
for (int n = 0; n < 1000; n++)
{
Future f = service.submit(new DoSomethingInAThread());
futures.add(f);
}
// wait for all tasks to complete before continuing
for (Future<Runnable> f : futures)
{
f.get();
}
//shut down the executor service so that this thread can exit
service.shutdownNow();
}
public void run()
{
// do something here
}
}
答案 3 :(得分:8)
完全避免使用Thread类,而是使用java.util.concurrent中提供的更高抽象
ExecutorService类提供的method invokeAll似乎可以满足您的需求。
答案 4 :(得分:8)
而不是join()
,这是一个旧API,您可以使用CountDownLatch。我已经修改了您的代码,以满足您的要求。
import java.util.concurrent.*;
class DoSomethingInAThread implements Runnable{
CountDownLatch latch;
public DoSomethingInAThread(CountDownLatch latch){
this.latch = latch;
}
public void run() {
try{
System.out.println("Do some thing");
latch.countDown();
}catch(Exception err){
err.printStackTrace();
}
}
}
public class CountDownLatchDemo {
public static void main(String[] args) {
try{
CountDownLatch latch = new CountDownLatch(1000);
for (int n=0; n<1000; n++) {
Thread t = new Thread(new DoSomethingInAThread(latch));
t.start();
}
latch.await();
System.out.println("In Main thread after completion of 1000 threads");
}catch(Exception err){
err.printStackTrace();
}
}
}
<强>解释强>:
CountDownLatch
已根据您的要求使用给定的数量1000进行初始化。
每个工作线程DoSomethingInAThread
将减少已在构造函数中传递的CountDownLatch
。
主线程CountDownLatchDemo
await()
,直到计数变为零。一旦计数变为零,您将获得输出线以下。
In Main thread after completion of 1000 threads
来自oracle文档页面的更多信息
public void await()
throws InterruptedException
导致当前线程等到锁存器倒计数到零,除非线程被中断。
有关其他选项,请参阅相关的SE问题:
答案 5 :(得分:5)
正如Martin K所说,java.util.concurrent.CountDownLatch
似乎是一个更好的解决方案。只需为同一个
public class CountDownLatchDemo
{
public static void main (String[] args)
{
int noOfThreads = 5;
// Declare the count down latch based on the number of threads you need
// to wait on
final CountDownLatch executionCompleted = new CountDownLatch(noOfThreads);
for (int i = 0; i < noOfThreads; i++)
{
new Thread()
{
@Override
public void run ()
{
System.out.println("I am executed by :" + Thread.currentThread().getName());
try
{
// Dummy sleep
Thread.sleep(3000);
// One thread has completed its job
executionCompleted.countDown();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
try
{
// Wait till the count down latch opens.In the given case till five
// times countDown method is invoked
executionCompleted.await();
System.out.println("All over");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
答案 6 :(得分:4)
考虑使用java.util.concurrent.CountDownLatch
。 javadocs
答案 7 :(得分:3)
如果你创建一个线程列表,你可以循环遍历它们和.join()对每个线程,你的循环将在所有线程完成时完成。我没试过。
http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join()
答案 8 :(得分:3)
根据您的需要,您可能还想查看java.util.concurrent包中的CountDownLatch和CyclicBarrier类。如果您希望线程彼此等待,或者您希望对线程执行方式进行更细粒度的控制(例如,在其内部执行中等待另一个线程设置某个状态),它们可能很有用。您还可以使用CountDownLatch来指示所有线程同时启动,而不是在迭代循环时逐个启动它们。标准API文档有一个这样的例子,加上另一个CountDownLatch等待所有线程完成它们的执行。
答案 9 :(得分:2)
这是一个评论,但我还不能做评论。
Martin K ,我很好奇你如何使用ThreadGroup
。你以前这样做过吗?
我看到上述情况,建议您查看activeCount
- 将 Martin v Löwis关注投票放在一边那一刻,我对activeCount
本身有另一种担忧。
警告:我没有尝试使用它,所以我不是这方面的专家,但根据javadocs,它返回活动线程数的估计 。
就个人而言,我不愿意尝试建立一个估计系统。你有另外想过怎么做,还是我误读了javadoc?
答案 10 :(得分:1)
在第一个for循环中创建线程对象。
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
// some code to run in parallel
}
});
threads[i].start();
}
那么大家都在这么说。
for(i = 0; i < threads.length; i++)
threads[i].join();
答案 11 :(得分:0)
答案 12 :(得分:0)
作为 CountDownLatch 的替代方案,您也可以使用 CyclicBarrier ,例如。
public class ThreadWaitEx {
static CyclicBarrier barrier = new CyclicBarrier(100, new Runnable(){
public void run(){
System.out.println("clean up job after all tasks are done.");
}
});
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new MyCallable(barrier));
t.start();
}
}
}
class MyCallable implements Runnable{
private CyclicBarrier b = null;
public MyCallable(CyclicBarrier b){
this.b = b;
}
@Override
public void run(){
try {
//do something
System.out.println(Thread.currentThread().getName()+" is waiting for barrier after completing his job.");
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
在这种情况下使用CyclicBarrier,barrier.await()应该是最后一个语句,即当你的线程完成其工作时。 CyclicBarrier可以再次使用其reset()方法。引用javadocs:
CyclicBarrier支持一个可选的Runnable命令,该命令在每个障碍点运行一次,在聚会中的最后一个线程到达之后,但在释放任何线程之前。在任何一方继续之前,此屏障操作对于更新共享状态非常有用。
答案 13 :(得分:0)
MainForm
对我没有帮助。在Kotlin中查看此示例:
join()
结果:
val timeInMillis = System.currentTimeMillis()
ThreadUtils.startNewThread(Runnable {
for (i in 1..5) {
val t = Thread(Runnable {
Thread.sleep(50)
var a = i
kotlin.io.println(Thread.currentThread().name + "|" + "a=$a")
Thread.sleep(200)
for (j in 1..5) {
a *= j
Thread.sleep(100)
kotlin.io.println(Thread.currentThread().name + "|" + "$a*$j=$a")
}
kotlin.io.println(Thread.currentThread().name + "|TaskDurationInMillis = " + (System.currentTimeMillis() - timeInMillis))
})
t.start()
}
})
现在让我将Thread-5|a=5
Thread-1|a=1
Thread-3|a=3
Thread-2|a=2
Thread-4|a=4
Thread-2|2*1=2
Thread-3|3*1=3
Thread-1|1*1=1
Thread-5|5*1=5
Thread-4|4*1=4
Thread-1|2*2=2
Thread-5|10*2=10
Thread-3|6*2=6
Thread-4|8*2=8
Thread-2|4*2=4
Thread-3|18*3=18
Thread-1|6*3=6
Thread-5|30*3=30
Thread-2|12*3=12
Thread-4|24*3=24
Thread-4|96*4=96
Thread-2|48*4=48
Thread-5|120*4=120
Thread-1|24*4=24
Thread-3|72*4=72
Thread-5|600*5=600
Thread-4|480*5=480
Thread-3|360*5=360
Thread-1|120*5=120
Thread-2|240*5=240
Thread-1|TaskDurationInMillis = 765
Thread-3|TaskDurationInMillis = 765
Thread-4|TaskDurationInMillis = 765
Thread-5|TaskDurationInMillis = 765
Thread-2|TaskDurationInMillis = 765
用于线程:
join()
结果:
val timeInMillis = System.currentTimeMillis()
ThreadUtils.startNewThread(Runnable {
for (i in 1..5) {
val t = Thread(Runnable {
Thread.sleep(50)
var a = i
kotlin.io.println(Thread.currentThread().name + "|" + "a=$a")
Thread.sleep(200)
for (j in 1..5) {
a *= j
Thread.sleep(100)
kotlin.io.println(Thread.currentThread().name + "|" + "$a*$j=$a")
}
kotlin.io.println(Thread.currentThread().name + "|TaskDurationInMillis = " + (System.currentTimeMillis() - timeInMillis))
})
t.start()
t.join()
}
})
很明显,当我们使用Thread-1|a=1
Thread-1|1*1=1
Thread-1|2*2=2
Thread-1|6*3=6
Thread-1|24*4=24
Thread-1|120*5=120
Thread-1|TaskDurationInMillis = 815
Thread-2|a=2
Thread-2|2*1=2
Thread-2|4*2=4
Thread-2|12*3=12
Thread-2|48*4=48
Thread-2|240*5=240
Thread-2|TaskDurationInMillis = 1568
Thread-3|a=3
Thread-3|3*1=3
Thread-3|6*2=6
Thread-3|18*3=18
Thread-3|72*4=72
Thread-3|360*5=360
Thread-3|TaskDurationInMillis = 2323
Thread-4|a=4
Thread-4|4*1=4
Thread-4|8*2=8
Thread-4|24*3=24
Thread-4|96*4=96
Thread-4|480*5=480
Thread-4|TaskDurationInMillis = 3078
Thread-5|a=5
Thread-5|5*1=5
Thread-5|10*2=10
Thread-5|30*3=30
Thread-5|120*4=120
Thread-5|600*5=600
Thread-5|TaskDurationInMillis = 3833
时:
我们防止阻塞其他线程的解决方案是创建ArrayList:
join
现在,当我们要启动一个新线程时,我们最多将其添加到ArrayList中:
val threads = ArrayList<Thread>()
addThreadToArray(
ThreadUtils.startNewThread(Runnable {
...
})
)
函数:
addThreadToArray
@Synchronized
fun addThreadToArray(th: Thread) {
threads.add(th)
}
功能:
startNewThread
在需要的地方检查线程的完成情况,如下所示:
fun startNewThread(runnable: Runnable) : Thread {
val th = Thread(runnable)
th.isDaemon = false
th.priority = Thread.MAX_PRIORITY
th.start()
return th
}