2017-05-28 2 views
3

J'ai trouvé que CompletableFuture :: semble se joindre ininterruptible quand pas terminé:Comment faire pour interrompre CompletableFuture :: join?

// CompletableFuture::join implementation from JDK 8 sources 
public T join() { 
    Object r; 
    return reportJoin((r = result) == null ? waitingGet(false) : r); 
} 

En application ci-dessus, waitingGet(false) ignorera le drapeau d'interruption du fil de travail et continuer à attendre. Je me demande comment je peux interrompre un Thread dans lequel j'appelle CompletableFuture :: join.

+1

Je me demande si c'est ce que vous cherchez: https://stackoverflow.com/questions/43389894/recursively-cancel-an-alloff-completablefuture/43391133#43391133 – Eugene

+1

@Eugene Merci pour le lien. Je sais que 'CompletableFuture :: cancel' n'interrompra pas le thread. Ce que je veux faire est d'interrompre un thread qui bloque dans une opération 'CompletableFuture :: join'. Peut-être devrais-je décrire ma question plus clairement. – phil

Répondre

5

N'utilisez pas join() si vous souhaitez prendre en charge l'interruption, utilisez plutôt get(). ils sont fondamentalement les mêmes, sauf:

  • join() provient de l'interface CompletionStage alors que get() vient interface sous forme Future
  • join() enveloppements exceptions CompletionException alors que get() les enveloppe dans ExecutionException
  • get() pourrait être interrompu et aurait alors jeter un InterruptedException

Notez que ce que vous interrompez est le Thread, pas le Future. Par exemple, le code suivant interrompt le thread principal alors qu'il est en attente sur myFuture.get():

CompletableFuture<Void> myFuture = new CompletableFuture<>(); 
Thread mainThread = Thread.currentThread(); 
CompletableFuture.runAsync(() -> { 
    try { 
     Thread.sleep(1000); 
     System.out.println("Interrupting…"); 
     mainThread.interrupt(); 
     Thread.sleep(1000); 
     System.out.println("Completing"); 
     myFuture.complete(null); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
}); 
try { 
    myFuture.get(); 
    System.out.println("Get succeeded"); 
} catch (Exception e) { 
    System.out.println("Get failed"); 
    e.printStackTrace(); 
} 

Sortie:

Interrupting… 
Get failed 
java.lang.InterruptedException 
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:347) 
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895) 
    at CompletableFutureInteruption.main(CompletableFutureInteruption.java:37) 
    … 

Si vous remplacez get() par join(), l'interruption sera en effet pas fonctionner.

+2

Merci d'avoir signalé les différences entre 'join()' et 'get()'. – phil

2

J'abandonne finalement pour interrompre le fil qui bloque en attendant la finition CompletableFuture::join.

Au lieu de cela, j'utiliser CompletableFuture::allof pour obtenir un CompletableFuturetous qui se termine lorsque tous mes finissent à terme jointes. Et puis il suffit d'appeler la méthode get() du tous Future dans le fil de travail. Lorsque get() revient, je collecte ensuite tous mes résultats en itérant tous mes Futures et je les appelle getNow. Une telle procédure est interruptible.

+0

On dirait que c'était [un problème XY] (https://meta.stackexchange.com/a/66378/167668) alors ... –

+0

@DidierL Oui, je veux juste une manière interruptible de "se joindre" à tous les Futures et d'obtenir le résultats. Je devrais clarifier avec ça. – phil

+0

Je ne vois pas comment 'allOf()' et les interruptions sont réellement liés les uns aux autres ici. Soit 'allOf()' résout le problème sans interruptions, ou vous avez besoin d'interruptions mais peu importe que vous travailliez sur le résultat d'un appel 'allOf()'. –