Search code examples
javaphaser

Phaser phase value escapes


Given, a class with main method that initializes a Phaser, and creates (say)3 Threads to count phases on the same Phaser.

public class PhaserDemo2 implements Runnable {

    private static Phaser CLASS_PHASER;
    private static int COUNTER;

    public static void main(String[] args) {
        COUNTER = 5;
        // create a Phaser and register main Thread
        CLASS_PHASER = new Phaser(1);
        System.out.println(Integer.MIN_VALUE);
        System.out.println("Phase value:" + CLASS_PHASER.getPhase() + ", Registered Parties:" 
                + CLASS_PHASER.getRegisteredParties() + ", and Counter:" + COUNTER);
        // create 3 Threads
        new Thread(new PhaserDemo2()).start();
        new Thread(new PhaserDemo2()).start();
        new Thread(new PhaserDemo2()).start();
        // de-register main Thread
        CLASS_PHASER.arriveAndDeregister();
    }

    @Override
    public void run() {
        // register the current Thread with Phaser
        CLASS_PHASER.register();
        // print details
        System.out.println("Phase value:" + CLASS_PHASER.getPhase() + ", Registered Parties:" 
                + CLASS_PHASER.getRegisteredParties() + ", and Counter:" + COUNTER);
        // wait till other Threads have printed as well
        CLASS_PHASER.arriveAndAwaitAdvance();
        // de-register this Thread
        CLASS_PHASER.arriveAndDeregister();
    }
}

The code works fine for most of executions, and produces output like below,

-2147483648
Phase value:0, Registered Parties:1, and Counter:5
Phase value:0, Registered Parties:2, and Counter:5
Phase value:1, Registered Parties:2, and Counter:5
Phase value:1, Registered Parties:3, and Counter:5

-2147483648
Phase value:0, Registered Parties:1, and Counter:5
Phase value:0, Registered Parties:2, and Counter:5
Phase value:0, Registered Parties:3, and Counter:5
Phase value:0, Registered Parties:3, and Counter:5

But for some odd executions, it produces output like below

-2147483648
Phase value:0, Registered Parties:1, and Counter:5
Phase value:0, Registered Parties:2, and Counter:5
Phase value:0, Registered Parties:3, and Counter:5
Phase value:-2147483646, Registered Parties:0, and Counter:5

-2147483648
Phase value:0, Registered Parties:1, and Counter:5
Phase value:0, Registered Parties:2, and Counter:5
Phase value:-2147483646, Registered Parties:0, and Counter:5
Phase value:-2147483646, Registered Parties:0, and Counter:5

-2147483648
Phase value:0, Registered Parties:1, and Counter:5
Phase value:-2147483647, Registered Parties:0, and Counter:5
Phase value:-2147483647, Registered Parties:0, and Counter:5
Phase value:-2147483647, Registered Parties:0, and Counter:5

I'm not sure if this can be successfully replicated or not, as this happens very rarely. Otherwise would like to know what incorrectness is causing this.
Declaration: just a beginner into Phaser


Solution

  • When you get a negative value as a phase value - your phase is terminated.

    Excerpt from Java doc for .getPhase() method:

    Returns the current phase number. The maximum phase number is Integer.MAX_VALUE, after which it restarts at zero. Upon termination, the phase number is negative, in which case the prevailing phase prior to termination may be obtained via getPhase() + Integer.MIN_VALUE.

    So, why this happens?

    From the same docs Termination section:

    Termination is triggered when an invocation of onAdvance returns true. The default implementation returns true if a deregistration has caused the number of registered parties to become zero.

    In your case, sometimes, the number of registered parties becomes 0. For example, it's possible, when you register the Main Thread, and while no one of your Threads has been registered - you deregister the Main thread. This case is:

    -2147483648
    Phase value:0, Registered Parties:1, and Counter:5
    Phase value:-2147483647, Registered Parties:0, and Counter:5
    Phase value:-2147483647, Registered Parties:0, and Counter:5
    Phase value:-2147483647, Registered Parties:0, and Counter:5
    

    Also, there is another case. Excerpt from baeldung:

    The call to the arriveAndAwaitAdvance() will cause the current thread to wait on the barrier. As already mentioned, when the number of arrived parties becomes the same as the number of registered parties, the execution will continue.

    And this case could be:

    -2147483648
    Phase value:0, Registered Parties:1, and Counter:5
    Phase value:0, Registered Parties:2, and Counter:5
    Phase value:-2147483646, Registered Parties:0, and Counter:5
    Phase value:-2147483646, Registered Parties:0, and Counter:5