Wie kann ich mit ScheduledExecutorService jeden Tag zu einer bestimmten Zeit bestimmte Aufgaben ausführen?


88

Ich versuche jeden Tag um 5 Uhr morgens eine bestimmte Aufgabe auszuführen. Also habe ich mich dafür entschieden, ScheduledExecutorServiceaber bisher habe ich Beispiele gesehen, die zeigen, wie man alle paar Minuten eine Aufgabe ausführt.

Und ich kann kein Beispiel finden, das zeigt, wie man eine Aufgabe jeden Tag zu einer bestimmten Zeit (5 Uhr morgens) ausführt und auch die Sommerzeit berücksichtigt -

Unten ist mein Code, der alle 15 Minuten ausgeführt wird -

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();
    }
}

Gibt es eine Möglichkeit, eine Aufgabe so zu planen, dass sie jeden Tag um 5 Uhr morgens ausgeführt wird, wobei auch ScheduledExecutorServicedie Sommerzeit berücksichtigt wird?

Und TimerTaskist auch besser dafür oder ScheduledExecutorService?


Verwenden Sie stattdessen etwas wie Quarz.
Millimoose

Antworten:


112

Wie bei der aktuellen Java SE 8-Version mit der hervorragenden Datums- und Uhrzeit-API kann java.timediese Art der Berechnung einfacher durchgeführt werden, anstatt java.util.Calendarund zu verwenden java.util.Date.

Als Beispiel für die Planung einer Aufgabe mit Ihrem Anwendungsfall:

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);

Das initalDelaywird berechnet, um den Scheduler zu bitten, die Ausführung in zu verzögern TimeUnit.SECONDS. Zeitdifferenzprobleme mit Millisekunden und darunter scheinen für diesen Anwendungsfall vernachlässigbar zu sein. Aber man kann immer noch Gebrauch machen duration.toMillis()und TimeUnit.MILLISECONDSdie Planungs computaions in Millisekunden für die Handhabung.

Und auch TimerTask ist besser für diesen oder ScheduledExecutorService?

NEIN: ScheduledExecutorService scheinbar besser als TimerTask. StackOverflow hat bereits eine Antwort für Sie .

Von @PaddyD,

Sie haben immer noch das Problem, dass Sie dies zweimal im Jahr neu starten müssen, wenn Sie möchten, dass es zur richtigen Ortszeit ausgeführt wird. ScheduleAtFixedRate wird es nicht schneiden, es sei denn, Sie sind das ganze Jahr über mit der gleichen UTC-Zeit zufrieden.

Da es stimmt und @PaddyD ihm bereits eine Problemumgehung gegeben hat (+1 für ihn), biete ich ein Arbeitsbeispiel mit der Java8-Datums- / Uhrzeit-API mit ScheduledExecutorService. Die Verwendung eines Daemon-Threads ist gefährlich

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);
        }
    }
}

Hinweis:

  • MyTaskist eine Schnittstelle mit Funktion execute.
  • Beim Anhalten ScheduledExecutorServiceimmer awaitTerminationnach dem Aufrufen verwenden shutdown: Es besteht immer die Wahrscheinlichkeit, dass Ihre Aufgabe stecken bleibt / blockiert und der Benutzer für immer warten würde.

Das vorherige Beispiel, das ich mit Calender gegeben habe, war nur eine Idee, die ich erwähnt habe. Ich habe genaue Zeitberechnungen und Probleme mit der Sommerzeit vermieden. Die Lösung wurde gemäß der Beschwerde von @PaddyD aktualisiert


Vielen Dank für den Vorschlag. Können Sie mir bitte ausführlich erklären, wie intDelayInHourich meine Aufgabe um 5 Uhr morgens ausführen kann?
AKIWEB

Was ist der Zweck von aDate?
José Andias

Aber wenn Sie dies bei HH: mm beginnen, wird die Aufgabe um 05: mm statt um 5 Uhr morgens ausgeführt? Die Sommerzeit wird auch nicht berücksichtigt, wie vom OP angefordert. Ok, wenn Sie es sofort nach der vollen Stunde starten oder wenn Sie mit einer Zeit zwischen 5 und 6 zufrieden sind oder wenn es Ihnen nichts ausmacht, die Anwendung mitten in der Nacht zweimal im Jahr neu zu starten, nachdem sich die Uhren geändert haben, nehme ich an ...
PaddyD

2
Sie haben immer noch das Problem, dass Sie dies zweimal im Jahr neu starten müssen, wenn Sie möchten, dass es zur richtigen Ortszeit ausgeführt wird. scheduleAtFixedRatewird es nicht schneiden, es sei denn, Sie sind das ganze Jahr über mit der gleichen UTC-Zeit zufrieden.
PaddyD

3
Warum wird der folgende (zweite) Beispieltrigger n-mal ausgeführt oder bis die Sekunde verstrichen ist? Sollte der Code nicht einmal täglich eine Aufgabe auslösen?
krizajb

24

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);

13
Zur besseren Lesbarkeit würde ich TimeUnit.DAYS.toMinutes(1)anstelle der "magischen Zahl" 1440
vorschlagen

Danke, Victor. Müssen Sie auf diese Weise zweimal im Jahr neu starten, wenn ich möchte, dass es zur richtigen Ortszeit ausgeführt wird?
invzbl3

Die feste Rate sollte sich nicht ändern, wenn sich die Ortszeit ändert. Nach der Erstellung wird sie ungefähr zur Rate.
Victor

Wie kommt es, dass dies meine Aufgabe um 23:59:59 auslöst?
krizajb

Zur besseren Lesbarkeit würde ich 1 anstelle von 1440 oder TimeUnit.DAYS.toMinutes (1) vorschlagen und dann die Zeiteinheit TimeUnit.DAYS verwenden. ;-)
Kelly Denehy

7

Wenn Sie nicht den Luxus haben, Java 8 verwenden zu können, können Sie Folgendes tun:

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();
   }
}

Es erfordert keine externen Bibliotheken und berücksichtigt die Sommerzeit. Geben Sie einfach die Tageszeit ein, zu der Sie die Aufgabe als CalendarObjekt und die Aufgabe als Objekt ausführen möchten Runnable. Zum Beispiel:

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");

Hinweis: Die Timer-Task wird in einem Daemon-Thread ausgeführt, der für E / A-Vorgänge nicht empfohlen wird. Wenn Sie einen Benutzer-Thread verwenden müssen, müssen Sie eine weitere Methode hinzufügen, mit der der Timer abgebrochen wird.

Wenn Sie a verwenden müssen ScheduledExecutorService, ändern Sie einfach die startTimerMethode wie folgt:

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

Ich bin mir des Verhaltens nicht sicher, aber Sie benötigen möglicherweise eine Stoppmethode, die aufgerufen wird, shutdownNowwenn Sie die ScheduledExecutorServiceRoute entlang gehen . Andernfalls kann Ihre Anwendung hängen bleiben, wenn Sie versuchen, sie zu stoppen.


Ich habe dich verstanden. +1 und danke. Es ist jedoch besser, wenn wir keinen Daemon-Thread (dh new Timer(runThreadName, true)) verwenden.
Salbei

@ Salbei keine Sorge. Ein Daemon-Thread ist in Ordnung, wenn Sie keine E / A ausführen. Der Anwendungsfall, für den ich dies geschrieben habe, war nur eine einfache Feuer-und-Vergessen-Klasse zum Starten einiger Threads, um einige tägliche Reinigungsaufgaben auszuführen. Ich nehme an, wenn Sie Datenbank-Lesevorgänge im Timer-Task-Thread ausführen, wie in der OP-Anforderung angegeben, sollten Sie keinen Daemon verwenden und benötigen eine Stoppmethode, die Sie aufrufen müssen, damit Ihre Anwendung beendet werden kann. stackoverflow.com/questions/7067578/…
PaddyD

@PaddyD War der letzte Teil, dh der mit ScheduledExecutorSerive, korrekt ??? Die Art und Weise, wie die anonyme Klasse erstellt wird, sieht syntaktisch nicht korrekt aus. Auch newSingleThreadExecutor () hätte keine Zeitplanmethode, oder?
FReeze FRancis

6

Haben Sie darüber nachgedacht, so etwas wie Quartz Scheduler zu verwenden ? Diese Bibliothek verfügt über einen Mechanismus zum Planen von Aufgaben, die jeden Tag zu einem festgelegten Zeitpunkt ausgeführt werden sollen, wobei ein Cron-ähnlicher Ausdruck verwendet wird (siehe CronScheduleBuilder).

Einige Beispielcodes (nicht getestet):

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();
    }
}

Es gibt ein bisschen mehr Arbeit im Voraus, und Sie müssen möglicherweise Ihren Jobausführungscode neu schreiben, aber es sollte Ihnen mehr Kontrolle darüber geben, wie Ihr Job ausgeführt werden soll. Es wäre auch einfacher, den Zeitplan zu ändern, falls dies erforderlich sein sollte.


5

Java8:
Meine Upgrage-Version von oben Antwort:

  1. Es wurde eine Situation behoben, in der der Webanwendungsserver aufgrund eines Threadpools mit inaktivem Thread nicht gestoppt werden möchte
  2. Ohne Rekursion
  3. Führen Sie die Aufgabe mit Ihrer benutzerdefinierten Ortszeit aus. In meinem Fall ist es Weißrussland, 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
Ich habe ähnliche Anforderungen. Ich muss die Aufgabe für einen Tag zu einer bestimmten Zeit planen. Sobald die geplante Aufgabe abgeschlossen ist, planen Sie die Aufgabe für den nächsten Tag zu einem bestimmten Zeitpunkt. Dies sollte weitergehen. Meine Frage ist, wie Sie herausfinden können, ob die geplante Aufgabe abgeschlossen ist oder nicht. Sobald ich weiß, dass die geplante Aufgabe abgeschlossen ist, kann nur ich den nächsten Tag planen.
Amitwdh

2

Ich hatte ein ähnliches Problem. Ich musste eine Reihe von Aufgaben planen, die während eines Tages ausgeführt werden sollten ScheduledExecutorService. Dies wurde durch eine Aufgabe gelöst, die um 3.30 Uhr begann und alle anderen Aufgaben relativ zu seiner aktuellen Zeit plante . Und sich für den nächsten Tag um 3:30 Uhr neu zu planen.

In diesem Szenario ist die Sommerzeit kein Problem mehr.


2

Sie können eine einfache Datumsanalyse verwenden. Wenn die Tageszeit vorher liegt, beginnen wir morgen:

  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

Nur um Victors Antwort zusammenzufassen .

Ich würde empfehlen, eine Prüfung hinzuzufügen, um festzustellen, ob die Variable (in seinem Fall die lange midnight) höher als ist 1440. Wenn ja, würde ich das weglassen .plusDays(1), sonst wird die Aufgabe erst übermorgen ausgeführt.

Ich habe es einfach so gemacht:

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;
}

Es vereinfacht sich, wenn SietruncatedTo()
Mark Jeronimus

1

Das folgende Beispiel funktioniert für mich

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);
    }
}

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


1

Sie können unter Klasse verwenden, um Ihre Aufgabe jeden Tag zu einer bestimmten Zeit zu planen

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
Bitte benutzen Sie nicht das veraltete Dateund TimeUnitim Jahr 2019
Mark Jeronimus

0

Was ist, wenn Ihr Server um 4:59 Uhr ausfällt und um 5:01 Uhr zurückkommt? Ich denke, es wird nur den Lauf überspringen. Ich würde einen dauerhaften Planer wie Quartz empfehlen, der seine Zeitplandaten irgendwo speichert. Dann wird es sehen, dass dieser Lauf noch nicht durchgeführt wurde und wird es um 5:01 Uhr tun.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.