Несоответствие ожидаемому результату работы IntStream

Рейтинг: -1Ответов: 1Опубликовано: 23.06.2023

Разбираюсь в многопоточности, дошёл до класса Phaser. Встретил пример.

Phaser phaser = new Phaser();
    IntStream.range(0, 3).forEach(i -> {
      phaser.register();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " " + phaser);
        }).start();
    });

Вывод работы этого кода:

Thread-1 java.util.concurrent.Phaser@42b4d62c[phase = 0 parties = 3 arrived = 0]
Thread-0 java.util.concurrent.Phaser@42b4d62c[phase = 0 parties = 3 arrived = 0]
Thread-2 java.util.concurrent.Phaser@42b4d62c[phase = 0 parties = 3 arrived = 0]

Сразу parties = 3 да и ещё в первой строке вывода. Думал будет reg() sout ,reg() sout, reg() sout() и parties = 1, parties = 2, parties = 3.

Искал в интернете(в т.ч. и в англоязычном) - ближе всего объяснение такого поведения в "планировщике", а там зарылся и тупик.

Может в не в ту степь пошёл: пробовал менять местами строки в этом куске кода, чтобы увидеть логику - безрезультатно.

Объясните, откуда программа знала, что parties = 3 до выполнения всего цикла (0,3)?

Ответы

▲ 1

Никакой магии нет. Привыкайте к асинхронности. Есть цикл, который выполняется в главном потоке и делает 2 операции - регистрирует участника и запускает новый поток. Запуск потока (вернее запуск и выполнение его Runnable) операция недешёвая и небыстрая. Тем более основной поток не дожидается самого факта запуска, скидывая эту проблему на JVM, и спокойненько идёт дальше выполнять цикл где снова меняет состояния фазера. К моменту, когда все 3 потока доходят до вывода на консоль, фазер уже зарегистрировал всех участников (ну или почти всех). Чтобы увидеть хронологию происходящего, достаточно расставить временные логи происходящего.

        IntStream.range(0, 3).forEach(i -> {
            phaser.register();
            System.out.println("Register: " + System.nanoTime());
            new Thread(() -> {
                System.out.println("Output:   " + System.nanoTime());
                System.out.println(Thread.currentThread().getName() + " " + phaser);
            }).start();
        });

ну и собственно логи

Register: 2452906851214400
Register: 2452906856518900
Register: 2452906856672000
Output:   2452906856816400
Output:   2452906856921500
Output:   2452906856968400