我有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
总是在第一个线程之后离开外部循环。
必须有一个解决该问题的简单方法
答案 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)
您想使用ExecutorService
和Future
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<>());