Обратный вызов java.util.concurrent.Phaser после завершения фазы

Я расследую Phaser от java.util.concurrent пакет и я написал пример кода:

public class ThreadsApp {

    public static void main(String[] args) {

        Phaser phaser = new Phaser(1);
        new Thread(new PhaseThread(phaser, "PhaseThread 1")).start();
        new Thread(new PhaseThread(phaser, "PhaseThread 2")).start();

        // ждем завершения фазы 0
        int phase = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();
        System.out.println("phase " + phase + " finished");
        // ждем завершения фазы 1
        phase = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();
        System.out.println("phase " + phase + " finished");

        // ждем завершения фазы 2
        phase = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();
        System.out.println("phase " + phase + " finished");

        phaser.arriveAndDeregister();
    }
}

class PhaseThread implements Runnable {

    Phaser phaser;
    String name;

    PhaseThread(Phaser p, String n) {

        this.phaser = p;
        this.name = n;
        phaser.register();
    }

    public void run() {
        try {
            System.out.println(name + " start execute phase " + phaser.getPhase());
            Thread.sleep(1000);
            phaser.arriveAndAwaitAdvance(); // сообщаем, что первая фаза достигнута

            System.out.println(name + " start execute phase " + phaser.getPhase());
            Thread.sleep(2000);
            phaser.arriveAndAwaitAdvance(); // сообщаем, что вторая фаза достигнута

            System.out.println(name + " start execute phase " + phaser.getPhase());
            Thread.sleep(3000);
            phaser.arriveAndDeregister(); // сообщаем о завершении фаз и удаляем с регистрации объекты

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

выход:

PhaseThread 2 start execute phase 0
PhaseThread 1 start execute phase 0
PhaseThread 2 start execute phase 1
phase 0 finished
PhaseThread 1 start execute phase 1
phase 1 finished
PhaseThread 1 start execute phase 2
PhaseThread 2 start execute phase 2
phase 2 finished

Вывод немного отличается от желаемого мной:

Мне нужно:

PhaseThread 2 start execute phase 0
PhaseThread 1 start execute phase 0
phase 0 finished
PhaseThread 2 start execute phase 1
PhaseThread 1 start execute phase 1
phase 1 finished
PhaseThread 1 start execute phase 2
PhaseThread 2 start execute phase 2
phase 2 finished

Таким образом, я хочу это phase X finished будет напечатан строго после обоих PhaseThread # start execute phase X и строгий перед PhaseThread # start execute phase X+1

Я понимаю, почему мой код работает неправильно, но я не знаю, как добиться желаемого поведения. Я думаю, что это возможно, потому что везде написано, что Phaser покрытие CyclicBarrier функциональность.

1 ответ

Чтение Java Doc для Phaser показывает переопределенный метод, называемый onAdvance который может быть использован для печати phase X finished когда фаза фактически закончена. Просто измените код, как показано ниже.

public class ThreadsApp {

    public static void main(String[] args) {

        Phaser phaser = new Phaser(1) {
            protected boolean onAdvance(int phase, int parties) { 
                System.out.println("phase " + phase + " finished");
                return false; 
            }
        };
        new Thread(new PhaseThread(phaser, "PhaseThread 1")).start();
        new Thread(new PhaseThread(phaser, "PhaseThread 2")).start();

        // ждем завершения фазы 0
        int phase = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();

        // ждем завершения фазы 1
        phase = phaser.getPhase();
        phaser.arriveAndAwaitAdvance();


        // ждем завершения фазы 2
        phase = phaser.getPhase();
        phaser.arriveAndDeregister();
    }
}

class PhaseThread implements Runnable {

    Phaser phaser;
    String name;

    PhaseThread(Phaser p, String n) {

        this.phaser = p;
        this.name = n;
        phaser.register();
    }

    public void run() {
        try {
            System.out.println(name + " start execute phase " + phaser.getPhase());
            Thread.sleep(1000);
            phaser.arriveAndAwaitAdvance(); // сообщаем, что первая фаза достигнута

            System.out.println(name + " start execute phase " + phaser.getPhase());
            Thread.sleep(2000);
            phaser.arriveAndAwaitAdvance(); // сообщаем, что вторая фаза достигнута

            System.out.println(name + " start execute phase " + phaser.getPhase());
            Thread.sleep(3000);
            phaser.arriveAndDeregister(); // сообщаем о завершении фаз и удаляем с регистрации объекты

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Другие вопросы по тегам