2016-04-26 1 views
3

Я пытаюсь увидеть поведение, которое целенаправленно вызывает переполнение стека с помощью CompletableFuture, но вместо этого выяснилось, это привело к успеху, и мой рекурсивный цикл просто остановился и вышел, а тест junit прошел. Это действительно не то поведение, которое я бы хотел. Я бы хотел, чтобы я работал с ошибкой, поэтому я знаю, как исправить мой код.Выдувание стека целиком с помощью CompletableFuture не привело к переполнению стека?

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

Я пытался отладить в затмении вокруг графа 1455, но затмение замерзает и не может загрузить трассировки стека, так что я не мог найти причину такого поведения.

Так что мои вопросы просто

  1. Является ли мой код как-то неправильно?
  2. Как успешно завершается успешное заполнениеFuture (или, возможно, это не то, как проходит мой тестовый пример junit).

Возможно, ОС имеет значение ... Я нахожусь на mac. Раньше у меня были собственные обещания, и они успешно ударяли стек.

ответ

1

thenAccept принимает Consumer и возвращает CompletableFuture<Void>. Если потребитель нормально возвращается без исключения, пустое будущее завершается нулевым. Если потребитель выдает исключение, то будущее будет завершено исключительно с этим исключением.

Если вы хотите поймать StackOverflowException, вам необходимо его вернуть из будущего. Есть много способов сделать это. Например:

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

или

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

ах, конечно ... что имеет смысл, так как исключение будет пойман .... прохладно, то есть больше, чем я ожидал. –

+0

hmmm, мне придется протестировать stackoverflow, а затем вызвать метод exceptionlyly (и переполнение стека файлов там). Интересно, как это обрабатывается. –

+0

Я не пробовал, но моя интерпретация документации Java API заключается в том, что второе исключение будет потеряно, и будущее будет завершено исходным исключением. Другими словами, если 'исключительное' генерирует исключение, это будет noop. –