Come aspettare che tutte le attività in un ThreadPoolExecutor finiscano senza interrompere l'esecutore?

Non posso usare shutdown() e awaitTermination() perché è ansible che nuovi task verranno aggiunti al ThreadPoolExecutor mentre è in attesa.

Quindi cerco un modo per aspettare che ThreadPoolExecutor abbia svuotato la sua coda e finito tutti i suoi compiti senza fermare nuovi compiti da aggiungere prima di quel punto.

  • Come uccidere un'applicazione di terze parti?
  • Android come creare lo stack tipo di sfondi di image
  • Parsing XML utilizzando kasoap2-Android
  • Eclipse Error su Mavericks: posix_spawn non è un meccanismo di lancio di process supportto su questa piattaforma
  • Android convertView, per utilizzarlo o no?
  • Accettazione SSL auto-firmata su Android
  • Se fa la differenza, questo è per Android.

    Grazie

    Aggiornamento : Molte settimane dopo dopo aver rivisitato questo, ho scoperto che un CountDownLatch modificato ha funzionato meglio per me in questo caso. Tengo la risposta contrassegnata perché si applica più a quello che ho chiesto.

  • Controlli severi di dipendenza Android in SDK 17
  • Rileva quando il frammento diventa visibile
  • Ottieni foto di contatti che sono sincronizzati con facebook per android
  • Come memorizzare i dati di sottoscrizione per la fatturazione Android in-app?
  • L'Android Systrace HTML nativo di React è vuoto in Ubuntu 14.04
  • imitando il cassetto di navigazione di youtube / gmail app
  • 6 Solutions collect form web for “Come aspettare che tutte le attività in un ThreadPoolExecutor finiscano senza interrompere l'esecutore?”

    Se sei interessato a sapere quando un determinato task è completato o un certo gruppo di attività, puoi utilizzare ExecutorService.submit(Runnable) . L'invocazione di questo metodo restituisce un object Future che può essere inserito in una Collection cui thread principale poi Future.get() su call Future.get() per ciascuno di essi. In questo modo il thread principale interromperà l'esecuzione finché l' ExecutorService ha elaborato tutte le attività Runnable .

     Collection<Future<?>> futures = new LinkedList<Future<?>>(); futures.add(executorService.submit(myRunnable)); for (Future<?> future:futures) { future.get(); } 

    Il mio scenario è un crawler web per recuperare alcune informazioni da un sito web e poi elaborarle. Un ThreadPoolExecutor viene utilizzato per accelerare il process perché molte pagine possono essere caricate nel tempo. Quindi nuove attività verranno create nell'attività esistente perché il crawler seguirà i collegamenti ipertestuali in each pagina. Il problema è lo stesso: il thread principale non sa quando tutti i compiti sono completati e può iniziare a elaborare il risultato. Io uso un modo semplice per determinare questo. Non è molto elegante ma funziona nel mio caso:

     while (executor.getTaskCount()!=executor.getCompletedTaskCount()){ System.err.println("count="+executor.getTaskCount()+","+executor.getCompletedTaskCount()); Thread.sleep(5000); } executor.shutdown(); executor.awaitTermination(60, TimeUnit.SECONDS); 

    Forse stai cercando un CompletionService per gestire batch di attività, vedere anche questa risposta .

    (Si tratta di un tentativo di riprodurre la precedente risposta eliminata di Thilo con i miei regolamenti.)

    Penso che potrebbe essere necessario chiarire la tua domanda in quanto vi è una condizione infinita implicita … a un certo punto si deve decidere di arrestare il tuo esecutore e a quel punto non accetterà più compiti. La tua domanda sembra implicare che si desidera attendere fino a quando non si sa che non saranno inviati ulteriori compiti, che puoi conoscere solo nel proprio codice di applicazione.

    La risposta seguente vi permetterà di passare senza problemi a un nuovo TPE (per qualunque ragione), completando tutte le attività attualmente presentate e non rifiutando nuove attività al nuovo TPE. Può rispondere alla tua domanda. @ Thilo potrebbe anche.

    Supponendo di aver definito da qualche parte un TPE visibile in uso come tale:

     AtomicReference<ThreadPoolExecutor> publiclyAvailableTPE = ...; 

    È quindi ansible scrivere la routine TPE swap come tale. Può anche essere scritto utilizzando un metodo sincronizzato, ma penso che questo sia più semplice:

     void rotateTPE() { ThreadPoolExecutor newTPE = createNewTPE(); // atomic swap with publicly-visible TPE ThreadPoolExecutor oldTPE = publiclyAvailableTPE.getAndSet(newTPE); oldTPE.shutdown(); // and if you want this method to block awaiting completion of old tasks in // the previously visible TPE oldTPE.awaitTermination(); } 

    In alternativa, se davvero non si scherza di voler uccidere il pool di thread, il tuo lato di presentatore dovrà affrontare le attività rifiutate ad un certo punto e potresti usare null per il nuovo TPE:

     void killTPE() { ThreadPoolExecutor oldTPE = publiclyAvailableTPE.getAndSet(null); oldTPE.shutdown(); // and if you want this method to block awaiting completion of old tasks in // the previously visible TPE oldTPE.awaitTermination(); } 

    Che potrebbe causare problemi a monte, il chiamante avrebbe bisogno di sapere cosa fare con un null .

    Potresti anche scambiare con un TPE fittizio che ha semplicemente rifiutato each nuova esecuzione, ma è equivalente a ciò che accade se chiama lo shutdown() sul TPE.

    Se non si desidera utilizzare l' shutdown , seguire gli approcci seguenti:

    1. Iterate attraverso tutti i compiti Future da submit su ExecutorService e controllare lo stato con la chiamata di block get() su object Future come suggerito da Tim Bender

    2. Utilizza uno dei

      1. Utilizzo di invokeAll su ExecutorService
      2. Utilizzo di CountDownLatch
      3. Utilizzando ForkJoinPool o newWorkStealingPool di Executors (da java 8)

    invokeAll() sul servizio esecutore ha anche lo stesso scopo di CountDownLatch

    Relazione SE:

    Come aspettare una serie di thread da completare?

    Potresti call waitTillDone () nella class Runner :

     Runner runner = Runner.runner(10); runner.runIn(2, SECONDS, runnable); runner.run(runnable); // each of this runnables could submit more tasks runner.waitTillDone(); // blocks until all tasks are finished (or failed) // and now reuse it runner.runIn(500, MILLISECONDS, callable); runner.waitTillDone(); runner.shutdown(); 

    Per usarlo aggiungi questa dipendenza gradle / maven al tuo progetto: 'com.github.matejtymes:javafixes:1.0'

    Per maggiori dettagli, consultare qui: https://github.com/MatejTymes/JavaFixes o qui: http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.