2016-04-26 7 views
3

Ich versuche zu sehen, das Verhalten absichtlich verursacht einen Stapelüberlauf mit CompletableFuture, aber stattdessen herausgefunden, es führte zum Erfolg und meine rekursive Schleife nur gestoppt und beendet und Junit Test bestanden. Das ist wirklich nicht das Verhalten, das ich möchte. Ich möchte ein schnelles Verhalten, also kann ich meinen Code reparieren.Den Stapel absichtlich mit CompleableFuture durchgebrannt ergab keinen Stapelüberlauf?

@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; 
} 

Ich habe versucht, in Eclipse um Zählung 1455 zu debuggen, aber gefriert verdunkeln und den Stack-Trace nicht geladen werden kann, damit ich nicht den Grund für dieses Verhalten finden konnte.

So sind meine Fragen einfach

  1. meinen Code irgendwie falsch sind?
  2. Wie wird die CompleableFuture erfolgreich beendet (oder ist es nicht in diesem Fall, wie ist mein Junit-Testfall)?

Vielleicht OS wichtig ... Ich bin auf einem Mac. Ich hatte vorher meine eigenen hausgemachten Versprechen und diese haben den Stapel erfolgreich durchgebrannt.

Antwort

1

thenAccept dauert eine Consumer und gibt eine CompletableFuture<Void> zurück. Wenn der Verbraucher normalerweise ohne Ausnahme zurückkehrt, wird die leere Zukunft mit Null abgeschlossen. Wenn der Verbraucher eine Ausnahme auslöst, wird die Zukunft ausnahmsweise mit dieser Ausnahme abgeschlossen.

Wenn Sie die StackOverflowException fangen wollen, müssen Sie es aus der zurückgegebenen Zukunft bekommen. Es gibt viele Möglichkeiten, dies zu tun. Zum Beispiel:

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

oder

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

ah, natürlich ..., die gefangen werden Sinn als die Ausnahme macht würde .... cool, das ist mehr, was ich erwartet hatte. –

+0

hmmm, ich werde stackoverflow testen müssen und dann die exceptionlly-Methode aufrufen (und force stack overflow). Ich frage mich, wie das gehandhabt wird. –

+0

Ich habe es nicht versucht, aber meine Interpretation der Java-API-Dokumentation ist, dass die zweite Ausnahme verloren gehen würde und die Zukunft mit der ursprünglichen Ausnahme abschließen würde. Mit anderen Worten, wenn "ausnahmsweise" eine Ausnahme auslöst, ist es ein Noop. –