【发布时间】:2020-07-01 05:34:46
【问题描述】:
我想了解 Java 中嵌套流之间的排序约束。
示例 1:
public static void main(String[] args) {
IntStream.range(0, 10).forEach(i -> {
System.out.println(i);
IntStream.range(0, 10).forEach(j -> {
System.out.println(" " + i + " " + j);
});
});
}
此代码确定性地执行,因此内部循环在每个j 上运行forEach,然后外部循环在下一个i 上运行自己的forEach:
0
0 0
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0 9
1
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
2
2 0
2 1
2 2
2 3
...
示例 2:
public static void main(String[] args) {
IntStream.range(0, 10).parallel().forEach(i -> {
System.out.println(i);
IntStream.range(0, 10).parallel().forEach(j -> {
System.out.println(" " + i + " " + j);
});
});
}
如果像第二个示例一样将流设为parallel(),我可以想象内部工作人员在等待线程在外部工作队列中可用时阻塞,因为外部工作队列线程必须在完成时阻塞内部流,默认线程池只有有限数量的线程。但是,死锁似乎没有发生:
6
5
8
8 6
0
1
6 2
7
1 6
8 5
7 6
8 8
2
0 6
0 2
0 8
5 2
5 4
5 6
0 5
2 6
7 2
7 5
7 8
6 4
8 9
1 5
...
两个流共享相同的默认线程池,但它们生成不同的工作单元。每个外部工作单元只能在该外部工作单元的所有内部单元完成后才能完成,因为每个并行流的末尾都有一个完成障碍。
如何在工作线程共享池中管理这些内部和外部流之间的协调,而不出现任何形式的死锁?
【问题讨论】:
-
“两个流”:不,这里有多个管道(至少 1+10)。为什么你认为这里需要在外部和内部流任务之间进行协调?唯一可以确定的事情是,对于任何给定的
i迭代,相应的j迭代将在i迭代完成之前运行,没有任何形式的保证顺序(对于i或@ 987654334@处决) -
@ernest_k 因为默认线程池中的工作线程数量有限,所有这些线程最终都会阻塞在外部流中,等待每个对应的内部流完成。但是,如果默认线程池中没有可以处理其项目的可用(空闲/静止)工作线程,则内部流无法完成——这会导致死锁。不过,请参阅 akuzminykh 的回复——显然这种死锁的可能性已被检测到,并根据需要创建了额外的工作线程。
标签: java multithreading java-stream