Come eseguire determinate attività ogni giorno in un determinato momento utilizzando ScheduledExecutorService?


90

Cerco di eseguire una determinata attività tutti i giorni alle 5 del mattino. Quindi ho deciso di utilizzare ScheduledExecutorServiceper questo, ma finora ho visto esempi che mostrano come eseguire l'attività ogni pochi minuti.

E non sono in grado di trovare alcun esempio che mostri come eseguire un'attività ogni giorno a un orario particolare (5 AM) del mattino e considerando anche l'ora legale -

Di seguito è riportato il mio codice che verrà eseguito ogni 15 minuti:

public class ScheduledTaskExample {
    private final ScheduledExecutorService scheduler = Executors
        .newScheduledThreadPool(1);

    public void startScheduleTask() {
    /**
    * not using the taskHandle returned here, but it can be used to cancel
    * the task, or check if it's done (for recurring tasks, that's not
    * going to be very useful)
    */
    final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
        new Runnable() {
            public void run() {
                try {
                    getDataFromDatabase();
                }catch(Exception ex) {
                    ex.printStackTrace(); //or loggger would be better
                }
            }
        }, 0, 15, TimeUnit.MINUTES);
    }

    private void getDataFromDatabase() {
        System.out.println("getting data...");
    }

    public static void main(String[] args) {
        ScheduledTaskExample ste = new ScheduledTaskExample();
        ste.startScheduleTask();
    }
}

Esiste un modo per programmare un'attività da eseguire ogni giorno alle 5:00 del mattino, ScheduledExecutorServiceconsiderando anche l'ora legale?

Ed TimerTaskè anche meglio per questo o ScheduledExecutorService?


Usa invece qualcosa come Quartz.
millimoose

Risposte:


113

Come con l'attuale versione di Java SE 8 con la sua eccellente API di data e ora, java.timequesto tipo di calcolo può essere fatto più facilmente invece di usare java.util.Calendare java.util.Date.

Ora come esempio di esempio per la pianificazione di un'attività con il tuo caso d'uso:

ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
ZonedDateTime nextRun = now.withHour(5).withMinute(0).withSecond(0);
if(now.compareTo(nextRun) > 0)
    nextRun = nextRun.plusDays(1);

Duration duration = Duration.between(now, nextRun);
long initalDelay = duration.getSeconds();

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);            
scheduler.scheduleAtFixedRate(new MyRunnableTask(),
    initalDelay,
    TimeUnit.DAYS.toSeconds(1),
    TimeUnit.SECONDS);

La initalDelayviene calcolata a chiedere lo scheduler di ritardare l'esecuzione in TimeUnit.SECONDS. I problemi di differenza di fuso orario con unità millisecondi e inferiori sembrano essere trascurabili per questo caso d'uso. È comunque possibile utilizzare duration.toMillis()e TimeUnit.MILLISECONDSper gestire i calcoli di pianificazione in millisecondi.

E anche TimerTask è meglio per questo o ScheduledExecutorService?

NO: ScheduledExecutorService apparentemente migliore di TimerTask. StackOverflow ha già una risposta per te .

Da @PaddyD,

Hai ancora il problema per cui devi riavviare questo due volte l'anno se vuoi che funzioni all'ora locale giusta. scheduleAtFixedRate non lo taglierà a meno che tu non sia soddisfatto della stessa ora UTC per tutto l'anno.

Poiché è vero e @PaddyD ha già fornito una soluzione alternativa (+1 a lui), sto fornendo un esempio funzionante con l'API di data e ora Java8 con ScheduledExecutorService. L'uso del thread daemon è pericoloso

class MyTaskExecutor
{
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    MyTask myTask;
    volatile boolean isStopIssued;

    public MyTaskExecutor(MyTask myTask$) 
    {
        myTask = myTask$;

    }

    public void startExecutionAt(int targetHour, int targetMin, int targetSec)
    {
        Runnable taskWrapper = new Runnable(){

            @Override
            public void run() 
            {
                myTask.execute();
                startExecutionAt(targetHour, targetMin, targetSec);
            }

        };
        long delay = computeNextDelay(targetHour, targetMin, targetSec);
        executorService.schedule(taskWrapper, delay, TimeUnit.SECONDS);
    }

    private long computeNextDelay(int targetHour, int targetMin, int targetSec) 
    {
        LocalDateTime localNow = LocalDateTime.now();
        ZoneId currentZone = ZoneId.systemDefault();
        ZonedDateTime zonedNow = ZonedDateTime.of(localNow, currentZone);
        ZonedDateTime zonedNextTarget = zonedNow.withHour(targetHour).withMinute(targetMin).withSecond(targetSec);
        if(zonedNow.compareTo(zonedNextTarget) > 0)
            zonedNextTarget = zonedNextTarget.plusDays(1);

        Duration duration = Duration.between(zonedNow, zonedNextTarget);
        return duration.getSeconds();
    }

    public void stop()
    {
        executorService.shutdown();
        try {
            executorService.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException ex) {
            Logger.getLogger(MyTaskExecutor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Nota:

  • MyTaskè un'interfaccia con funzioni execute.
  • Durante l'arresto ScheduledExecutorService, usa sempre awaitTerminationdopo averlo richiamato shutdown: c'è sempre una probabilità che la tua attività sia bloccata / in fase di stallo e l'utente aspetterà per sempre.

L'esempio precedente che ho fornito con Calender era solo un'idea che ho menzionato, ho evitato il calcolo esatto dell'ora e problemi di risparmio legale. Aggiornata la soluzione in base al reclamo di @PaddyD


Grazie per il suggerimento, puoi spiegarmi in dettaglio come intDelayInHoursignifica che eseguirò il mio compito alle 5 del mattino?
AKIWEB

Qual è lo scopo di aDate?
José Andias

Ma se lo inizi a HH: mm l'attività verrà eseguita alle 05: mm anziché alle 5 del mattino? Inoltre non tiene conto dell'ora legale come richiesto dall'OP. Ok se lo avvii subito dopo l'ora, o se sei soddisfatto di un qualsiasi momento tra le 5 e le 6, o se non ti dispiace riavviare l'applicazione nel cuore della notte due volte l'anno dopo che gli orologi sono cambiati suppongo ...
PaddyD

2
Hai ancora il problema per cui devi riavviare questo due volte l'anno se vuoi che funzioni all'ora locale giusta. scheduleAtFixedRatenon lo taglierà a meno che tu non sia soddisfatto della stessa ora UTC tutto l'anno.
PaddyD

3
Perché il seguente trigger di esempio (secondo) viene eseguito n volte o finché il secondo non viene superato? Il codice non doveva attivare l'attività una volta al giorno?
krizajb,

25

In Java 8:

scheduler = Executors.newScheduledThreadPool(1);

//Change here for the hour you want ----------------------------------.at()       
Long midnight=LocalDateTime.now().until(LocalDate.now().plusDays(1).atStartOfDay(), ChronoUnit.MINUTES);
scheduler.scheduleAtFixedRate(this, midnight, 1440, TimeUnit.MINUTES);

14
Per la leggibilità suggerirei TimeUnit.DAYS.toMinutes(1)invece del "numero magico" 1440.
filono

Grazie, Victor. In questo modo è necessario riavviare due volte l'anno se voglio che funzioni alla giusta ora locale?
invzbl3

il tasso fisso non dovrebbe cambiare quando cambia l'ora locale, dopo aver creato, diventa circa il tasso.
Victor

Come mai questo innesca il mio compito alle 23:59:59?
krizajb

Per la leggibilità suggerirei 1 invece di 1440 o TimeUnit.DAYS.toMinutes (1), quindi utilizzare l'unità di tempo TimeUnit.DAYS. ;-)
Kelly Denehy

7

Se non hai il lusso di poter utilizzare Java 8, quanto segue farà quello che ti serve:

public class DailyRunnerDaemon
{
   private final Runnable dailyTask;
   private final int hour;
   private final int minute;
   private final int second;
   private final String runThreadName;

   public DailyRunnerDaemon(Calendar timeOfDay, Runnable dailyTask, String runThreadName)
   {
      this.dailyTask = dailyTask;
      this.hour = timeOfDay.get(Calendar.HOUR_OF_DAY);
      this.minute = timeOfDay.get(Calendar.MINUTE);
      this.second = timeOfDay.get(Calendar.SECOND);
      this.runThreadName = runThreadName;
   }

   public void start()
   {
      startTimer();
   }

   private void startTimer();
   {
      new Timer(runThreadName, true).schedule(new TimerTask()
      {
         @Override
         public void run()
         {
            dailyTask.run();
            startTimer();
         }
      }, getNextRunTime());
   }


   private Date getNextRunTime()
   {
      Calendar startTime = Calendar.getInstance();
      Calendar now = Calendar.getInstance();
      startTime.set(Calendar.HOUR_OF_DAY, hour);
      startTime.set(Calendar.MINUTE, minute);
      startTime.set(Calendar.SECOND, second);
      startTime.set(Calendar.MILLISECOND, 0);

      if(startTime.before(now) || startTime.equals(now))
      {
         startTime.add(Calendar.DATE, 1);
      }

      return startTime.getTime();
   }
}

Non richiede librerie esterne e terrà conto dell'ora legale. Passa semplicemente l'ora del giorno in cui desideri eseguire l'attività come Calendaroggetto e l'attività come file Runnable. Per esempio:

Calendar timeOfDay = Calendar.getInstance();
timeOfDay.set(Calendar.HOUR_OF_DAY, 5);
timeOfDay.set(Calendar.MINUTE, 0);
timeOfDay.set(Calendar.SECOND, 0);

new DailyRunnerDaemon(timeOfDay, new Runnable()
{
   @Override
   public void run()
   {
      try
      {
        // call whatever your daily task is here
        doHousekeeping();
      }
      catch(Exception e)
      {
        logger.error("An error occurred performing daily housekeeping", e);
      }
   }
}, "daily-housekeeping");

NB l'attività timer viene eseguita in un thread Daemon che non è consigliato per eseguire operazioni di I / O. Se è necessario utilizzare un thread utente, sarà necessario aggiungere un altro metodo che annulli il timer.

Se devi usare a ScheduledExecutorService, cambia semplicemente il startTimermetodo come segue:

private void startTimer()
{
   Executors.newSingleThreadExecutor().schedule(new Runnable()
   {
      Thread.currentThread().setName(runThreadName);
      dailyTask.run();
      startTimer();
   }, getNextRunTime().getTime() - System.currentTimeMillis(),
   TimeUnit.MILLISECONDS);
}

Non sono sicuro del comportamento, ma potresti aver bisogno di un metodo di arresto che chiama shutdownNowse segui il ScheduledExecutorServicepercorso, altrimenti la tua applicazione potrebbe bloccarsi quando provi a fermarla.


Ho capito il tuo punto. +1 e grazie. Tuttavia, è meglio se non usiamo il thread Daemon (cioè new Timer(runThreadName, true)).
Sage

@Sage non preoccuparti. Un thread daemon va bene se non stai facendo alcun IO. Il caso d'uso per cui ho scritto questo era solo una semplice lezione di fuoco e dimentica per avviare alcuni thread per eseguire alcune attività di pulizia quotidiana. Suppongo che se stai eseguendo letture del database nel thread dell'attività del timer come potrebbe indicare la richiesta di OP, non dovresti usare un Daemon e avrai bisogno di un qualche tipo di metodo di arresto che dovrai chiamare per abilitare la terminazione dell'applicazione. stackoverflow.com/questions/7067578/...
PaddyD

@PaddyD L'ultima parte, ovvero quella che utilizza ScheduledExecutorSerive, era corretta ??? Il modo in cui viene creata la classe anonima non sembra corretta per quanto riguarda la sintassi. Anche newSingleThreadExecutor () non avrebbe il metodo di pianificazione giusto ??
FReeze FRancis

6

Hai pensato di utilizzare qualcosa come Quartz Scheduler ? Questa libreria ha un meccanismo per la pianificazione delle attività da eseguire in un determinato periodo di tempo ogni giorno utilizzando un'espressione simile a cron (dai un'occhiata CronScheduleBuilder).

Qualche codice di esempio (non testato):

public class GetDatabaseJob implements InterruptableJob
{
    public void execute(JobExecutionContext arg0) throws JobExecutionException
    {
        getFromDatabase();
    }
}

public class Example
{
    public static void main(String[] args)
    {
        JobDetails job = JobBuilder.newJob(GetDatabaseJob.class);

        // Schedule to run at 5 AM every day
        ScheduleBuilder scheduleBuilder = 
                CronScheduleBuilder.cronSchedule("0 0 5 * * ?");
        Trigger trigger = TriggerBuilder.newTrigger().
                withSchedule(scheduleBuilder).build();

        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.scheduleJob(job, trigger);

        scheduler.start();
    }
}

C'è un po 'più di lavoro in anticipo e potrebbe essere necessario riscrivere il codice di esecuzione del lavoro, ma dovrebbe darti un maggiore controllo su come desideri che venga eseguito il lavoro. Inoltre sarebbe più facile cambiare il programma se necessario.


5

Java8: la
mia versione upgrage dalla risposta principale:

  1. Risolto il problema quando il server di applicazioni Web non si desiderava arrestare, a causa del threadpool con thread inattivo
  2. Senza ricorsione
  3. Esegui l'attività con l'ora locale personalizzata, nel mio caso, è la Bielorussia, Minsk


/**
 * Execute {@link AppWork} once per day.
 * <p>
 * Created by aalexeenka on 29.12.2016.
 */
public class OncePerDayAppWorkExecutor {

    private static final Logger LOG = AppLoggerFactory.getScheduleLog(OncePerDayAppWorkExecutor.class);

    private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

    private final String name;
    private final AppWork appWork;

    private final int targetHour;
    private final int targetMin;
    private final int targetSec;

    private volatile boolean isBusy = false;
    private volatile ScheduledFuture<?> scheduledTask = null;

    private AtomicInteger completedTasks = new AtomicInteger(0);

    public OncePerDayAppWorkExecutor(
            String name,
            AppWork appWork,
            int targetHour,
            int targetMin,
            int targetSec
    ) {
        this.name = "Executor [" + name + "]";
        this.appWork = appWork;

        this.targetHour = targetHour;
        this.targetMin = targetMin;
        this.targetSec = targetSec;
    }

    public void start() {
        scheduleNextTask(doTaskWork());
    }

    private Runnable doTaskWork() {
        return () -> {
            LOG.info(name + " [" + completedTasks.get() + "] start: " + minskDateTime());
            try {
                isBusy = true;
                appWork.doWork();
                LOG.info(name + " finish work in " + minskDateTime());
            } catch (Exception ex) {
                LOG.error(name + " throw exception in " + minskDateTime(), ex);
            } finally {
                isBusy = false;
            }
            scheduleNextTask(doTaskWork());
            LOG.info(name + " [" + completedTasks.get() + "] finish: " + minskDateTime());
            LOG.info(name + " completed tasks: " + completedTasks.incrementAndGet());
        };
    }

    private void scheduleNextTask(Runnable task) {
        LOG.info(name + " make schedule in " + minskDateTime());
        long delay = computeNextDelay(targetHour, targetMin, targetSec);
        LOG.info(name + " has delay in " + delay);
        scheduledTask = executorService.schedule(task, delay, TimeUnit.SECONDS);
    }

    private static long computeNextDelay(int targetHour, int targetMin, int targetSec) {
        ZonedDateTime zonedNow = minskDateTime();
        ZonedDateTime zonedNextTarget = zonedNow.withHour(targetHour).withMinute(targetMin).withSecond(targetSec).withNano(0);

        if (zonedNow.compareTo(zonedNextTarget) > 0) {
            zonedNextTarget = zonedNextTarget.plusDays(1);
        }

        Duration duration = Duration.between(zonedNow, zonedNextTarget);
        return duration.getSeconds();
    }

    public static ZonedDateTime minskDateTime() {
        return ZonedDateTime.now(ZoneId.of("Europe/Minsk"));
    }

    public void stop() {
        LOG.info(name + " is stopping.");
        if (scheduledTask != null) {
            scheduledTask.cancel(false);
        }
        executorService.shutdown();
        LOG.info(name + " stopped.");
        try {
            LOG.info(name + " awaitTermination, start: isBusy [ " + isBusy + "]");
            // wait one minute to termination if busy
            if (isBusy) {
                executorService.awaitTermination(1, TimeUnit.MINUTES);
            }
        } catch (InterruptedException ex) {
            LOG.error(name + " awaitTermination exception", ex);
        } finally {
            LOG.info(name + " awaitTermination, finish");
        }
    }

}

1
Ho un requisito simile. Devo programmare un'attività per un giorno in un determinato momento. Una volta completata l'attività pianificata, pianifica l'attività per il giorno successivo a una determinata ora. Questo dovrebbe continuare ad andare avanti. La mia domanda è come scoprire che l'attività pianificata è stata completata o meno. Una volta che so che l'attività pianificata è stata completata, solo io posso programmare per il giorno successivo.
amitwdh

2

Ho avuto un problema simile. Ho dovuto programmare una serie di attività che dovrebbero essere eseguite durante una giornata utilizzando ScheduledExecutorService. Questo problema è stato risolto da un'attività che inizia alle 3:30 AM pianificando tutte le altre attività relativamente all'ora corrente . E riprogrammare se stesso per il giorno successivo alle 3:30.

Con questo scenario l'ora legale non è più un problema.


2

Puoi utilizzare una semplice analisi della data, se l'ora del giorno è precedente a adesso, iniziamo domani:

  String timeToStart = "12:17:30";
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss");
  SimpleDateFormat formatOnlyDay = new SimpleDateFormat("yyyy-MM-dd");
  Date now = new Date();
  Date dateToStart = format.parse(formatOnlyDay.format(now) + " at " + timeToStart);
  long diff = dateToStart.getTime() - now.getTime();
  if (diff < 0) {
    // tomorrow
    Date tomorrow = new Date();
    Calendar c = Calendar.getInstance();
    c.setTime(tomorrow);
    c.add(Calendar.DATE, 1);
    tomorrow = c.getTime();
    dateToStart = format.parse(formatOnlyDay.format(tomorrow) + " at " + timeToStart);
    diff = dateToStart.getTime() - now.getTime();
  }

  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);            
  scheduler.scheduleAtFixedRate(new MyRunnableTask(), TimeUnit.MILLISECONDS.toSeconds(diff) ,
                                  24*60*60, TimeUnit.SECONDS);

1

Solo per sommare la risposta di Victor .

Consiglierei di aggiungere un segno di spunta per vedere se la variabile (nel suo caso la long midnight) è maggiore di 1440. Se lo è, ometterei il .plusDays(1), altrimenti l'attività verrà eseguita solo dopodomani.

L'ho fatto semplicemente così:

Long time;

final Long tempTime = LocalDateTime.now().until(LocalDate.now().plusDays(1).atTime(7, 0), ChronoUnit.MINUTES);
if (tempTime > 1440) {
    time = LocalDateTime.now().until(LocalDate.now().atTime(7, 0), ChronoUnit.MINUTES);
} else {
    time = tempTime;
}

Si semplifica se si fa uso ditruncatedTo()
Mark Jeronimus

1

Il seguente esempio funziona per me

public class DemoScheduler {

    public static void main(String[] args) {

        // Create a calendar instance
        Calendar calendar = Calendar.getInstance();

        // Set time of execution. Here, we have to run every day 4:20 PM; so,
        // setting all parameters.
        calendar.set(Calendar.HOUR, 8);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.AM_PM, Calendar.AM);

        Long currentTime = new Date().getTime();

        // Check if current time is greater than our calendar's time. If So,
        // then change date to one day plus. As the time already pass for
        // execution.
        if (calendar.getTime().getTime() < currentTime) {
            calendar.add(Calendar.DATE, 1);
        }

        // Calendar is scheduled for future; so, it's time is higher than
        // current time.
        long startScheduler = calendar.getTime().getTime() - currentTime;

        // Setting stop scheduler at 4:21 PM. Over here, we are using current
        // calendar's object; so, date and AM_PM is not needed to set
        calendar.set(Calendar.HOUR, 5);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.AM_PM, Calendar.PM);

        // Calculation stop scheduler
        long stopScheduler = calendar.getTime().getTime() - currentTime;

        // Executor is Runnable. The code which you want to run periodically.
        Runnable task = new Runnable() {

            @Override
            public void run() {

                System.out.println("test");
            }
        };

        // Get an instance of scheduler
        final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        // execute scheduler at fixed time.
        scheduler.scheduleAtFixedRate(task, startScheduler, stopScheduler, MILLISECONDS);
    }
}

riferimento: https://chynten.wordpress.com/2016/06/03/java-scheduler-to-run-every-day-on-specific-time/


1

Puoi usare la lezione sottostante per programmare la tua attività ogni giorno in un determinato momento

package interfaces;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class CronDemo implements Runnable{

    public static void main(String[] args) {

        Long delayTime;

        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        final Long initialDelay = LocalDateTime.now().until(LocalDate.now().plusDays(1).atTime(12, 30), ChronoUnit.MINUTES);

        if (initialDelay > TimeUnit.DAYS.toMinutes(1)) {
            delayTime = LocalDateTime.now().until(LocalDate.now().atTime(12, 30), ChronoUnit.MINUTES);
        } else {
            delayTime = initialDelay;
        }

        scheduler.scheduleAtFixedRate(new CronDemo(), delayTime, TimeUnit.DAYS.toMinutes(1), TimeUnit.MINUTES);

    }

    @Override
    public void run() {
        System.out.println("I am your job executin at:" + new Date());
    }
}

1
Si prega di non utilizzare l'obsoleto Datee TimeUnitnel 2019
Mark Jeronimus

0

Cosa succede se il tuo server si arresta alle 4:59 e torna alle 5:01? Penso che salterà la corsa. Consiglierei uno scheduler persistente come Quartz, che memorizzerebbe i suoi dati di pianificazione da qualche parte. Quindi vedrà che questa corsa non è stata ancora eseguita e lo farà alle 5:01.


0

Perché complicare una situazione se puoi scrivere così? (si -> bassa coesione, hardcoded -> ma è un esempio e purtroppo con imperativo). Per ulteriori informazioni leggere l'esempio di codice in basso;))

package timer.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.concurrent.*;

public class TestKitTimerWithExecuterService {

    private static final Logger log = LoggerFactory.getLogger(TestKitTimerWithExecuterService.class);

    private static final ScheduledExecutorService executorService 
= Executors.newSingleThreadScheduledExecutor();// equal to => newScheduledThreadPool(1)/ Executor service with one Thread

    private static ScheduledFuture<?> future; // why? because scheduleAtFixedRate will return you it and you can act how you like ;)



    public static void main(String args[]){

        log.info("main thread start");

        Runnable task = () -> log.info("******** Task running ********");

        LocalDateTime now = LocalDateTime.now();

        LocalDateTime whenToStart = LocalDate.now().atTime(20, 11); // hour, minute

        Duration duration = Duration.between(now, whenToStart);

        log.info("WhenToStart : {}, Now : {}, Duration/difference in second : {}",whenToStart, now, duration.getSeconds());

        future = executorService.scheduleAtFixedRate(task
                , duration.getSeconds()    //  difference in second - when to start a job
                ,2                         // period
                , TimeUnit.SECONDS);

        try {
            TimeUnit.MINUTES.sleep(2);  // DanDig imitation of reality
            cancelExecutor();    // after canceling Executor it will never run your job again
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("main thread end");
    }




    public static void cancelExecutor(){

        future.cancel(true);
        executorService.shutdown();

        log.info("Executor service goes to shut down");
    }

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.