Domanda

ho questo piuttosto semplice domanda sul ThreadPoolExecutor . Ho la seguente situazione: devo consumare gli oggetti da una coda, creare le attività dei lavoratori appropriata per loro e li presenta al ThreadPoolExecutor. Questo è abbastanza semplice. Ma all'interno di uno scenario di arresto molti i lavoratori possono essere messi in coda per l'esecuzione. Dal momento che uno di quei compiti potrebbe essere in esecuzione per un'ora, e voglio un arresto relativly veloce grazioso dell'applicazione voglio scartare tutte le attività in coda dal ThreadPoolExecutor mentre i compiti già di elaborazione dovrebbe essere completato normalmente.

La documentazione ThreadPoolExecutor ha una metodo remove (), ma consente solo compiti specifici da rimuovere. spurgo () funziona solo per le attività future già cancellato. La mia idea era quella di cancellare la coda tenendo tutti i compiti in coda. Il ThreadPoolExecutor fornisce l'accesso a questa coda interna, ma la documentazione afferma:

  

Metodo getQueue () consente l'accesso al   coda di lavoro per fini di monitoraggio   e il debug. L'utilizzo di questo metodo   per qualsiasi altro scopo è fortemente   scoraggiato.

Quindi, afferrare la coda e di compensazione non è un'opzione. Inoltre, questo frammento di documentazione dice:

  

Due metodi forniti,   rimuovere (java.lang.Runnable) e spurgo ()   sono disponibili per assistere in deposito   bonifica, quando un gran numero di   compiti in coda diventano annullata.

Come? Certo, posso mantenere un elenco di tutte le attività ho presentato al l'esecutore e in un caso di spegnimento i iterare su tutte le voci e rimuoverli dal ThreadPoolExecutor con il metodo remove () ... ma ... dai, questo è un spreco di memoria e una seccatura per mantenere questa lista. (Rimozione compiti già eseguiti, per esempio)

Mi rendo conto eventuali suggerimenti o soluzioni!

È stato utile?

Soluzione

Avete considerato avvolgendo l'ExecutorService? Creare un

CleanShutdownExecutorService implements Executor 

che i delegati di tutte le chiamate verso un altro esecutore, ma mantiene i Futures in una lista propria. CleanShutdownExecutorService può quindi avere un metodo cancelRemainingTasks () che chiama shutdown (), allora chiamate annullare (false) su tutte le future nel suo elenco.

Altri suggerimenti

Ho usato per lavorare su un app con lunghi fili in esecuzione. Lo facciamo allo spegnimento,

BlockingQueue<Runnable> queue = threadPool.getQueue();
List<Runnable> list = new ArrayList<Runnable>();
int tasks = queue.drainTo(list);

L'elenco viene salvato in un file. All'avvio, viene aggiunto alla lista torna alla piscina in modo da non perdere alcun lavoro.

ExecutorService. shutdown () non sta facendo abbastanza e ExecutorService.shutdownNow () sta facendo troppo immagino si deve scrivere qualcosa nel mezzo:. ricordare tutte le attività presentate e rimuoverli manualmente dopo (o prima) di chiamare shutdown()

Questa è una vecchia questione, ma nel caso in cui questo aiuta qualcun altro: è possibile impostare un valore booleano volatile, quando si chiama shutdown (), e hanno ogni attività presentata terminare se questo booleana viene impostata prima di iniziare davvero. Questo permetterà compiti che hanno veramente cominciato a completare, ma impedirà compiti in coda di iniziare la propria attività reale.

La risposta di Bombe è esattamente quello che vuoi. shutdownNow() ferma tutto utilizzando il Nuke e spianare approccio. Questa è la cosa migliore che puoi fare, a corto di sottoclassi l'attuazione di ThreadPoolExecutor che si sta utilizzando.

Si può provare allowCoreThreadTimeOut(true);

Si potrebbe creare il proprio compito della coda e passarlo al costruttore ThreadPoolExecutor:

int poolSize = 1; // number of threads
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>();
Executor executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue);

Quando si cancella la coda da qualche parte nel codice, allora non verranno eseguite le attività rimanenti:

queue.clear();

Una soluzione folle e impuro che potrebbe funzionare (il pensiero non reale tramite o testate) sarebbe quello di sovrascrivere il interrupt() dei tuoi WorkerTasks cui solo nel caso in cui è impostato un valore globale di rifiutare di arresto quando interrupt() viene chiamato su di loro da shutdownNow () .

Questo dovrebbe consentire di utilizzare shutdownNow() no?

Informi il pool di thread per spegnere, getQueue, for-each il risultato in singoli Runnables, rimuovere ogni Runnable utilizzando il metodo di rimozione. A seconda del tipo di coda, si potrebbe essere in grado di fermare le rimuove presto sulla base di valori di ritorno.

In sostanza, questo sta afferrando la coda e di compensazione esso, solo la compensazione tramite i metodi che funzionano. Invece di ricordare manualmente tutte le osservazioni, si utilizza il fatto il pool di thread ha già di ricordare tutte le osservazioni. Tuttavia, si avrà probabilmente bisogno di fare una copia di difesa della coda, in quanto penso che sia una visione dal vivo, e la rimozione di conseguenza probabilmente causare un'eccezione modifica concomitante se si stesse iterazione / per-NSEGNARE il live view.

Non awaitTermination(long timeout, TimeUnit unit) lavoro dopo l'arresto?

executor.shutdown (); executor.awaitTermination (60, TimeUnit.SECONDS)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top