Creare prima l'esecutore.
Avete diverse possibilità.
Se suppongo che le tue attività implementino un'interfaccia semplice per interrogare il loro stato (qualcosa come un enum con 'NeedReschedule' o 'Completed'), quindi implementa un wrapper (implementando Runnable
) per le tue attività che prenderanno il compito e l'esecutore come parametri di instanciazione. Questo wrapper eseguirà l'attività a cui è associato, verificherà il suo stato in seguito e, se necessario, riprogrammerà una copia di se stesso nell'esecutore prima di terminare.
In alternativa, è possibile utilizzare un meccanismo di execption per segnalare al wrapper che l'attività deve essere riprogrammata. Questa soluzione è più semplice, nel senso che non richiede una particolare interfaccia per il tuo compito, così che il semplice Runnable
possa essere lanciato nel sistema senza problemi. Tuttavia, le eccezioni comportano più tempo di calcolo (costruzione di oggetti, traccia dello stack ecc.).
Ecco una possibile implementazione del wrapper utilizzando il meccanismo di segnalazione delle eccezioni. È necessario implementare la classe RescheduleException
che estende Throwable
, che può essere attivata dall'esecuzione eseguibile (non è necessaria un'interfaccia più specifica per l'attività in questa configurazione). Puoi anche usare un semplice RuntimeException
come proposto in un'altra risposta, ma dovrai testare la stringa del messaggio per sapere se questa è l'eccezione che stai aspettando.
public class TaskWrapper implements Runnable {
private final ExecutorService executor;
private final Runnable task;
public TaskWrapper(ExecutorService e, Runnable t){
executor = e;
task = t;
}
@Override
public void run() {
try {
task.run();
}
catch (RescheduleException e) {
executor.execute(this);
}
}
Ecco un'applicazione molto semplice cottura fino a 200 operazioni avvolto in modo casuale chiedendo un riprogrammare.
class Task implements Runnable {
@Override
public void run(){
if (Maths.random() > 0.5)
throw new RescheduleException();
}
}
public class Main {
public static void main(String[] args){
ExecutorService executor = Executors.newFixedThreadPool(10);
int i = 200;
while(i--)
executor.execute(new TaskWrapper(executor, new Task());
}
}
si potrebbe anche avere un thread dedicato per monitorare gli altri thread risultati (utilizzando una coda di messaggi) e riprogrammare se necessario, ma si perde un thread, rispetto alle altre soluzioni.
Basta creare una nuova attività uguale a quella corrente e metterla in coda. Termina compito corrente – hoaz
@hoaz: vuoi dire riferimento l'esecutore all'interno delle attività? – Cratylus
@Cratylus - sì, se l'attività ha un riferimento indietro all'esecutore, potrebbe ri-accodarsi. assicurati solo che la coda dei compiti in attesa dell'esecutore non sia limitata o che tu possa finire per bloccarti. – jtahlborn