Domanda

Sto provando a trasferire il codice dall'uso di java timer all'utilizzo di scheduledexecutorservice

Ho il seguente caso d'uso

class A {

    public boolean execute() {
         try {
              Timer t = new Timer();
              t.schedule (new ATimerTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}


class B {

    public boolean execute() {
         try {
              Timer t = new Timer();
              t.schedule (new BTimerTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}

Devo semplicemente sostituire le istanze Timer in classe A e classe B con ScheduledExecutorService e rendere la classe ATimerTask e BTimerTask in una classe Runnable, ad esempio

class B {

    public boolean execute() {
         try {
              final ScheduledExecutorService scheduler = 
   Executors.newScheduledThreadPool(1);

              scheduler.scheduleWithFixedDelay (new BRunnnableTask(), period, delay);
         } catch (Exception e) {
              return false;
         }
    }

}

È corretto.

EDIT: una delle principali motivazioni del porting è che le eccezioni di runtime lanciate in TimerTask uccidono quel thread e non possono essere programmate ulteriormente. Voglio evitare il caso in modo che, anche se ho un'eccezione di runtime, il thread dovrebbe continuare a essere eseguito e non arrestarsi.

È stato utile?

Soluzione

NOTA: il modo in cui lo hai fatto perderà i thread!

Se la tua classe B sarà mantenuta in giro e ogni istanza alla fine verrà chiusa o chiusa o rilasciata, lo farei così:

class B {
  final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

  public boolean execute() {
    try {
      scheduler.scheduleWithFixedDelay(new BRunnnableTask(), period, delay);
      return true;
    } catch (Exception e) {
      return false;
    }
  }

  public void close() {
    scheduler.shutdownNow();
  }
}

Se non eseguirai questo tipo di pulizia su ogni istanza, farei invece questo:

class B {
  static final ScheduledExecutorService SCHEDULER = Executors.newCachedThreadPool();

  public boolean execute() {
    try {
      SCHEDULER.scheduleWithFixedDelay(new BRunnnableTask(), period, delay);
      return true;
    } catch (Exception e) {
      return false;
    }
  }
}

Ogni ExecutorService che assegni nel tuo codice alloca un singolo Thread . Se crei molte istanze della tua classe B , a ciascuna istanza verrà assegnato un Thread . Se questi non raccolgono rapidamente la spazzatura, allora puoi finire con molte migliaia di thread allocati (ma non utilizzati, appena allocati) e puoi arrestare l'intero server, facendo morire di fame ogni processo sulla macchina, non solo la tua JVM. L'ho visto accadere su Windows e mi aspetto che possa succedere anche su altri sistemi operativi.

Un pool di thread nella cache statica è molto spesso una soluzione sicura quando non si intende utilizzare i metodi del ciclo di vita sulle singole istanze di oggetti, poiché si manterranno solo tutti i thread che sono effettivamente in esecuzione e non uno per ogni istanza che crei che non è ancora stata raccolta in modo inutile.

Altri suggerimenti

Sembra ok. A seconda di cosa stai facendo, potresti voler mantenere il servizio di esecutore come membro in modo da poterlo riutilizzare. Inoltre, è possibile recuperare un ScheduledFuture dai metodi scheduleXX (). Questo è utile perché puoi richiamare get () su di esso per estrarre eventuali eccezioni che si verificano nel thread a tempo nel thread di controllo per la gestione.

Al momento non esiste un buon modo per gestire le attività ricorrenti nel framework Executors.

In realtà non è stato progettato tenendo presente questo caso d'uso e non esiste un modo realistico per evitare di ingoiare eccezioni.

Se devi davvero usarlo per ripetere le attività, ogni pianificazione dovrebbe assomigliare a questa:

scheduler.scheduleWithFixedDelay(new Runnable() {
  public void run() {
     try {
       .. your normal code here...
     } catch (Throwable t) {
       // handle exceptions there
     }
  }
}, period, delay);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top