Во время игры с параллельными потоками Java у меня возникали взаимоблокировки, когда некоторые параллельные операции выполнялись в статическом блоке инициализатора.
При использовании последовательного потока все работает нормально:
import java.util.Arrays;
public class Example1 {
static {
// displays the numbers from 1 to 10 ordered => no thread issue
Arrays.asList(1,2,3,4,5,6,7,8,9,10)
.forEach(s->System.out.println(s));
}
public static final void main(String[] args) {}
}
При параллельной обработке потока каждая работа (числа отображаются без порядка):
import java.util.Arrays;
public class Example2 {
static {
// displays the numbers from 1 to 10 unordered => no thread issue
Arrays.asList(1,2,3,4,5,6,7,8,9,10).parallelStream()
.forEach(s->System.out.println(s));
}
public static final void main(String[] args) {}
}
Однако при обработке потока с помощью forEachOrdered()
возникает тупик (я полагаю, это связано с взаимодействием между основным потоком и управлением ForkJoinPool):
import java.util.Arrays;
public class Example3 {
static {
// hangs forever (deadlock between the main thread which loads the class and the underlying ForkJoinPool which join several tasks)
Arrays.asList(1,2,3,4,5,6,7,8,9,10).parallelStream()
.forEachOrdered(s->System.out.println(s));
}
public static final void main(String[] args) {}
}
Но при порождении потоковой обработки в отдельном потоке все идет хорошо:
import java.util.Arrays;
public class Example4 {
static {
// displays the numbers from 1 to 10 ordered => no thread issue
new Thread(()->
Arrays.asList(1,2,3,4,5,6,7,8,9,10).parallelStream()
.forEachOrdered(s->System.out.println(s))
).start();
}
public static final void main(String[] args) {}
}
Из того, что я видел из дампа потоков, основной поток ожидает на ForkJoinPool, используемом в .forEachOrdered()
, чтобы завершить свою работу, но первый рабочий поток в пуле заблокирован, ожидая чего-то (скорее всего, заблокирован main
)
Мне бы очень хотелось понять, почему в некоторых случаях возникает тупик, а не в других. Это, очевидно, не только из-за использования статического блока инициализатора, параллельного потока и лямбды, потому что Example2
, Example3
и Example4
используют эти три понятия, но только Example3
вызывает тупик.
Хотя этот вопрос может выглядеть как дубликат Почему параллельный поток с лямбдой в статическом инициализаторе вызывает тупик? , это не так. Мой вопрос выходит за рамки связанного, поскольку он предоставляет Example2
, для которого у нас есть статический блок инициализатора, параллельный поток и лямбда, но нет тупика. Вот почему заголовок вопроса содержит «может привести к тупику, но не обязательно».