2016-04-26 4 views
3

Je suis en train de voir le comportement de causer délibérément un débordement de pile avec CompletableFuture mais découvert, il a donné lieu à succès et ma boucle récursive juste arrêté et est sorti et test JUnit passé. Ce n'est vraiment pas le comportement que je voudrais. Je voudrais un comportement rapide, donc je sais réparer mon code.Souffler intentionnellement la pile avec CompletableFuture n'a pas provoqué de débordement de pile?

@Test 
public void testBlowTheStack() throws InterruptedException { 
    recurse(0); 

    System.out.println("done"); 
    Thread.sleep(5000); 
} 


private void recurse(int counter) { 
    CompletableFuture<Integer> future = writeData(counter); 
    future.thenAccept(p -> recurse(p+1));  
} 

private CompletableFuture<Integer> writeData(int counter) { 
    System.out.println("counter="+counter); 
    if(counter == 1455) { 
     System.out.println("mark"); 
    } 

    CompletableFuture<Integer> future = new CompletableFuture<Integer>(); 
    future.complete(counter); 
    return future; 
} 

J'ai essayé de déboguer dans Eclipse autour de comptage 1455, mais éclipse se fige et ne peut pas charger la trace de la pile, donc je ne pouvais pas trouver la raison derrière ce comportement.

Mes questions sont simples

  1. mon code incorrect d'une certaine manière?
  2. comment est le CompletableFuture sortir avec succès (ou peut-être il est dans ce cas, comment est mon cas test JUnit passage).

Peut-être importe OS ... Je suis sur un mac. Auparavant, j'avais mes propres promesses maison et ceux qui réussissent à sauter la pile.

Répondre

1

thenAccept prend un Consumer et renvoie un CompletableFuture<Void>. Si le consommateur revient normalement sans exception, le futur vide est complété par null. Si le consommateur émet une exception, l'avenir est exceptionnellement complété avec cette exception.

Si vous voulez attraper le StackOverflowException dont vous avez besoin pour obtenir de l'avenir retourné. Il y a plusieurs façons de le faire. Par exemple:

future.thenAccept(p -> recurse(p+1)).join(); 

ou

future.thenAccept(p -> recurse(p+1)) 
     .exceptionally(e -> { 
      e.printStackTrace(); 
      return null; 
     }); 
+0

ah, bien sûr ... qui fait sens que l'exception serait pris .... cool, qui est plus ce que je pensais. –

+0

hmmm, je vais devoir tester stackoverflow puis appeler la méthode exceptionlly (et le débordement de la pile de force là-bas) .. Je me demande comment cela est géré. –

+0

Je ne l'ai pas essayé, mais mon interprétation de la documentation de l'API Java est que la deuxième exception serait perdue et l'avenir compléterait à l'exception d'origine. En d'autres termes, si 'exceptionnellement' renvoie une exception c'est un noop. –