Java等待多个线程,可能会创建新的线程

时间:2018-01-04 09:47:59

标签: java multithreading

我有Thread A,会创建new Thread B。 此Thread B可能会创建new Threads,也可能会创建new Threads。 我的thread A需要等待所有其他线程完成。

我的第一次尝试是将所有线程添加到列表中。

private List<TestcaseExecutionThread> threads = new CopyOnWriteArrayList<>();
// inside my run function
Iterator<TestcaseExecutionThread> it = threads.iterator();

while (it.hasNext()) {
    TestcaseExecutionThread t = it.next();
    while (t.isRunning()) {
        try {
            TimeUnit.MILLISECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
    }
}

Thread A遍历列表的所有元素,只是在循环中调用一个函数,返回列表中的当前线程仍在运行。 在第一个线程完成后使用正常ArrayList,这将进入Deadlock。 然后我使用了CopyOnWriteArrayList,但是Thread A总是在第一个线程之后离开外部循环。

必须有一个解决该问题的简单方法

4 个答案:

答案 0 :(得分:3)

您可以使用Phaser来完成此操作。我已经将逻辑包装在一个新的类MyThread中,您应该在需要您正在寻找的行为的任何地方使用Thread来代替它:

class MyThread extends Thread
{
    MyThread(final Runnable runnable, final Phaser phaser)
    {
        super(() -> {
            runnable.run();
            phaser.arrive();
        });
        phaser.register();
    }
}

以下是示例用法。主线程创建一个线程(“A”),它本身创建一个线程(“B”)。主线程等待所有线程完成:

public static void main(String[] args)
{
    final Phaser phaser = new Phaser(1);

    new MyThread(
        () -> {
            new MyThread(() -> System.out.println("B"), phaser).start();
            System.out.println("A");
            try
            {
                Thread.sleep(1000); // wait for 1s to prove main thread is really waiting
            }
            catch (InterruptedException e) {}
        },
        phaser
    ).start();

    phaser.arriveAndAwaitAdvance();

    System.out.println("Everything is done");
}

答案 1 :(得分:1)

我会抛弃最不具侵入性的方法来解决这个问题。替换它。

private List<TestcaseExecutionThread> threads = new CopyOnWriteArrayList<>();

使用队列

private Queue<TestcaseExecutionThread> threads = new LinkedList<>();

现在你的循环应该是:

while (threads.size()>0) {
    TestcaseExecutionThread t = threads.poll();
    while (t.isRunning()) {
         try {
            TimeUnit.MILLISECONDS.sleep(1);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
    }
}

真的,你的&#34;线程&#34;应该是Queue<Future<?>>,那么你不需要内部while循环。但这将涉及改变结构,而不是调用&#34;线程#start&#34;您可以将其提交给执行者服务,并将返回的未来添加到队列中。

答案 2 :(得分:0)

您想使用ExecutorServiceFuture s。

ExecutorService service = Executors.newFixedThreadPool(4); // or similar

public void run() {
    List<Future<?> futures = runnables.stream().map(service::submit).collect(toList());
    futures.forEach(Future::get);
}

这会针对您的每个ExecutorService.submit致电Runnable,然后在每个返回的get上致电Future,以便所有执行都在最后完成。

正如亚特评论的那样,它确实听起来像ForkJoinPool是更好的方法,但这取决于你的实际可运行。

答案 3 :(得分:0)

您可以使用同步列表:

map()

和索引:

private List<Thread> threads = Collections.synchronizedList(new ArrayList<>());