1

I have a spring @Controller that has a request mapping. When requests are sent to it it creates a deferred result and runs a method on a delegator class.

In the controller:

@ResponseBody
@RequestMapping(MenuModelCodes.MENU_NAME)
DeferredResult<HttpEntity<?>> getModelCodesWithClass(String target) {
    final DeferredResult<HttpEntity<?>> deferredResult = getNewDeferredResult();
    delegator.doStuff(target);
    return deferredResult;
}

The doStuff method in the delegator is @Async annotated - so it's running in another thread. In this thread a new Phaser is created to keep track of child threads it will create. The delegator thread itself registers with the phaser, and triggers a call to a method in "AnotherClass" that is also @Async annotated. I.e. the delegator is now spawning children.

The delegator:

public class Delegator {

    @Async
    public Object doStuff(String requestURI)  {

        Phaser phaser = new Phaser();
        phaser.register();
        Object result = anotherClass.createThreadDoWork(phaser);
        phaser.arriveAndDeregister();

        //Wait until phaser is completed
        while (!phaser.isTerminated()) {}

        return result;
    }
}

Each child spawned thread created by a call in the delegator to createThreadDoWork here registers itself with the phaser, does some work and then arrives and deregisters.

AnotherClass:

public class AnotherClass {
    @Async
    public void createThreadDoWork(Phaser phaser) throws Throwable {        
        phaser.register();
        //some kind of logic / rest call etc.
        phaser.arriveAndDeregister();
    }
}

When all child threads complete, the delegator which is sitting at this piece of code:

while (!phaser.isTerminated()) {}

Will continue, set its deferred result and the delegator thread will end.

So here's the question(s):

I want a Phaser for every request - i.e. I create a new Phaser() everytime a request creates a new delegator thread.

If I receive 5 requests to my controller, they each spawn a delegator thread, each delegator creates a new Phaser and passes it to their children. However, as soon as one of the threads completes its processing and its specific instance of the Phaser is terminated, the other delegator threads continue and return without having done their tasks.

Can Phasers be used like this? Am I doing something wrong? I thought this would be a useful way to track the completion of child threads and wait for them to complete?

Thanks.

jacomus
  • 51
  • 2

1 Answers1

0

Can Phasers be used like this?

Yes, it can be used like this, and usually would be as a synchronization barrier.


Am I doing something wrong?

Yes. Do not do

while (!phaser.isTerminated()) {}

The busy spinning will kill you. Instead do:

phaser.awaitAdvance();

This would force you to register a little differently. You would have to register a thread before you actually start running.

Also if you are in advancing the phaser where you have a multiple phases then you would have to re-evaluate using a phaser.


I thought this would be a useful way to track the completion of child threads and wait for them to complete?

If you do have a number of unknown threads being created it would be useful to use a Phaser.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • Thanks, I removed the phaser.register() in the delegator and just simply put phaser.arriveAndAwaitAdvance() after the anotherClass.createThreadDoWork(phaser) call and that's fine. But it's only fine for one call. As soon as second request arrives, and creates a new phaser and starts processing, if the original delegator thread advances the phaser the second request/thread will exit. Any ideas? – jacomus Jun 18 '14 at 13:45
  • Java 7 docs also seem to think phaser.register(); while (!phaser.isTerminated()) phaser.arriveAndAwaitAdvance(); is an acceptable usage approach? – jacomus Jun 18 '14 at 13:57
  • That would be better since you are not busy spinning. You are still awaiting on the phasers completion. – John Vint Jun 18 '14 at 14:09
  • I guess the main question is, can 2 instances of Phaser act independently? i.e. if all parties to one phaser arrive, does that cause the phase on the other to increment? Or is the phase of every Phaser specific to the instance of that phaser only? – jacomus Jun 18 '14 at 14:22
  • The latter. The only case in which that isn't true is if one Phaser is a parent of a child (ie: `new Phaser(new Phaser())`) – John Vint Jun 18 '14 at 14:32
  • Two Phasers are like two CountdownLatches or two CyclicBarriers. Acting on one will not effect the others. – John Vint Jun 18 '14 at 14:33