Domanda

Ho inviato un'attività usando gli esecutori e ho bisogno che si fermi dopo un po 'di tempo (ad es. 5 minuti). Ho provato a fare così:

   for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
         try {
             fut.get(); 
         } catch (CancellationException ex) {
             fut.cancel(true);   
             tasks.clear();
         } catch(ExecutionException ex){
             ex.printStackTrace(); //FIXME: gestita con printstack       
         }
   }

Ma ricevo sempre un errore: ho un vettore condiviso che deve essere modificato dalle attività e quindi letto da un thread, e anche se interrompo tutte le attività, se si verifica il timeout ottengo:

Exception in thread "Thread-1" java.util.ConcurrentModificationException

C'è qualcosa che non va? Come posso interrompere le attività inviate che funzionano ancora dopo 5 minuti?

È stato utile?

Soluzione

Solo perché chiami cancel () su Future non significa che l'attività si interromperà automaticamente. Devi fare un po 'di lavoro all'interno dell'attività per assicurarti che si fermi:

  • Usa cancel (true) in modo che un interrupt venga inviato all'attività.
  • Gestisci InterruptedException . Se una funzione nella tua attività genera un InterruptedException , assicurati di uscire con garbo il più presto possibile dopo aver rilevato l'eccezione.
  • Controlla periodicamente Thread.currentThread (). isInterrupted () se l'attività esegue il calcolo continuo.

Ad esempio:

class LongTask implements Callable<Double> {
    public Double call() {

         // Sleep for a while; handle InterruptedException appropriately
         try {
             Thread.sleep(10000);
         } catch (InterruptedException ex) {
             System.out.println("Exiting gracefully!");
             return null;
         }


         // Compute for a while; check Thread.isInterrupted() periodically
         double sum = 0.0;
         for (long i = 0; i < 10000000; i++) {
             sum += 10.0
             if (Thread.currentThread().isInterrupted()) {
                 System.out.println("Exiting gracefully");
                 return null;
             }
         }

         return sum;
    } 
}

Inoltre, come altri articoli hanno menzionato: ConcurrentModificationException può essere lanciato anche se si utilizza la classe Vector thread-safe, perché gli iteratori ottenuti da Vector non sono thread-safe e quindi devono essere sincronizzati. Il for-loop avanzato utilizza iteratori, quindi fai attenzione:

final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);

// Not thread safe!  If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
    System.out.println(num);
}

// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) {    // "vector" must be final
    for (Double num : vector) {
        System.out.println(num);
    }
}

Altri suggerimenti

Il ConcurrentModificationException proviene dalla tua chiamata a task.clear () mentre i tuoi Exceutor stanno ripetendo le tue attività Vector . Quello che puoi provare a fare è chiamare shutdownNow () sul tuo ExecutorService

Il caso più comune di ConcurrentModificationException è quando il vettore viene modificato contemporaneamente alla sua iterazione. Spesso questo sarà fatto in un singolo thread. È necessario tenere premuto un blocco sul Vector per l'intera iterazione (e fare attenzione a non deadlock).

fut.get () è una chiamata bloccante, anche dopo il timeout, si bloccherà fino al completamento dell'attività. Se vuoi fermarti il ??più vicino possibile al segno dei 5 minuti, devi controllare il flag di interruzione, ti consiglio solo di farlo usando il metodo Thread.isInterrupted () che conserva lo stato di interruzione. Se vuoi fermarti immediatamente e non hai bisogno di pulire nessuno stato, lancia un'eccezione che verrà catturata dal futuro e ti verrà indicata come ExecutionException.

fut.cancel (true) non fa nulla in quanto il metodo invokeAll () lo ha già fatto per te.

A meno che tu non usi le " attività " Raccolta da qualche altra parte, probabilmente non è necessario chiamare clear () su di esso. Questo non sarà la fonte del tuo problema poiché il metodo invokeAll () è fatto con la Lista quando chiami clear (). Ma, se devi iniziare a formare un elenco di nuove attività da eseguire, ti suggerisco di formare un nuovo Elenco di attività, non utilizzare un vecchio Elenco di nuove attività.

Sfortunatamente, non ho una risposta per il tuo problema. Non vedo abbastanza informazioni qui per diagnosticare. Nulla nello snippet di codice fornito indica un uso improprio (solo non necessario) delle classi / metodi della libreria. Forse se hai incluso una traccia dello stack completo, anziché l'errore di una riga.

Inserisci fut.cancel (true); nel blocco finally

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