ScheduledExecutorService'i kullanarak her gün belirli bir saatte belirli bir görev nasıl çalıştırılır?


90

Her gün sabah 5'de belirli bir görevi yerine getirmeye çalışıyorum. Bunun için kullanmaya karar verdim ScheduledExecutorServiceama şimdiye kadar birkaç dakikada bir görevin nasıl çalıştırılacağını gösteren örnekler gördüm.

Her gün belirli bir saatte (5 AM) bir görevin nasıl çalıştırılacağını gösteren ve ayrıca gün ışığından yararlanma saati gerçeğini de göz önünde bulunduran bir örnek bulamıyorum

Her 15 dakikada bir çalışacak olan kodum aşağıdadır -

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

Herhangi bir şekilde, gün ScheduledExecutorServiceışığından yararlanma saati gerçeğini de dikkate alarak her gün sabah 05: 00'te çalışacak bir görev planlayabilir miyim ?

Ve ayrıca TimerTaskbunun için daha ScheduledExecutorServicemı iyi ?


Bunun yerine Quartz gibi bir şey kullanın.
millimoose

Yanıtlar:


113

İle 's mükemmel tarih saat API ile mevcut java SE 8 bırakma gibi java.timehesaplama bu tür kullanmak yerine daha kolay yapılabilir java.util.Calendarve java.util.Date.

Şimdi, kullanım durumunuzla bir görevi planlamak için örnek bir örnek olarak:

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

initalDelayİçinde yürütülmesine geciktirmek için zamanlayıcı sormaya hesaplanır TimeUnit.SECONDS. Birim milisaniye ve altındaki zaman farkı sorunları bu kullanım durumu için ihmal edilebilir görünüyor. Ama yine de milisaniye cinsinden planlama hesaplamalarını kullanabilir duration.toMillis()ve TimeUnit.MILLISECONDSişleyebilirsiniz.

Ve ayrıca TimerTask bunun için mi yoksa ScheduledExecutorService mi?

HAYIR: ScheduledExecutorService Görünüşe göre daha iyi TimerTask. StackOverflow'un sizin için zaten bir cevabı var .

@PaddyD'den,

Hala, doğru yerel saatte çalışmasını istiyorsanız, bunu yılda iki kez yeniden başlatmanız gereken bir sorun yaşıyorsunuz. schedAtFixedRate, tüm yıl aynı UTC saatinden memnun olmadığınız sürece kesmez.

Doğru olduğu ve @PaddyD zaten bir geçici çözüm (ona +1) vermiş olduğu için, Java8 tarih saat API'si ile çalışan bir örnek sunuyorum ScheduledExecutorService. Daemon thread kullanmak tehlikelidir

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

Not:

  • MyTaskişlevi olan bir arayüzdür execute.
  • Durdururken ScheduledExecutorService, Her zaman onu awaitTerminationçağırdıktan sonra kullanın shutdown: Görevinizin takılma / kilitlenme olasılığı her zaman vardır ve kullanıcı sonsuza kadar bekleyecektir.

Calender ile verdiğim önceki örnek sadece bahsettiğim bir fikirdi , tam saat hesaplama ve Günışığı tasarrufu sorunlarından kaçındım. @PaddyD şikayetine göre çözüm güncellendi


Öneriniz için teşekkürler, lütfen bana intDelayInHourgörevimi sabah 5'te nasıl yürüteceğimi ayrıntılı olarak açıklar mısınız?
AKIWEB

ADate'in amacı nedir?
José Andias

Ancak buna SS: mm'den başlarsanız, görev 05: 00'da değil, 05: mm'de çalıştırılacak mı? Ayrıca OP'nin talep ettiği gün ışığından yararlanma saatini hesaba katmaz. Tamam, bir saatten hemen sonra başlatırsanız veya 5 ile 6 arasında herhangi bir zamandan memnunsanız veya saatler değiştikten sonra yılda iki kez uygulamayı gece yarısı yeniden başlatmanın sakıncası yoksa, sanırım ...
PaddyD

2
Hala doğru yerel saatte çalışmasını istiyorsanız, bunu yılda iki kez yeniden başlatmanız gereken bir sorun yaşıyorsunuz. scheduleAtFixedRateTüm yıl aynı UTC saatinden memnun olmadığınız sürece kesmez.
PaddyD

3
Aşağıdaki örnek (ikinci) neden n kez veya ikincisi geçene kadar tetikleme yapıyor? Kodun her gün bir görevi tetiklemesi gerekmiyor muydu?
krizajb

25

Java 8'de:

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
Okunabilirlik TimeUnit.DAYS.toMinutes(1)için "sihirli sayı" 1440 yerine öneririm .
Philonous

Teşekkürler Victor. Bu şekilde, doğru yerel saatte çalışmasını istersem yılda iki kez yeniden başlatmam gerekir mi?
invzbl3

sabit oran, yerel saat değiştiğinde değişmemelidir, oluşturulduktan sonra oranla ilgili hale gelir.
Victor

Bu 23:59:59'daki görevimi nasıl tetikliyor?
krizajb

Okunabilirlik için 1440 veya TimeUnit.DAYS.toDAYS (1) yerine 1 öneririm ve ardından TimeUnit.DAYS zaman birimini kullanırdım. ;-)
Kelly Denehy

7

Java 8'i kullanma lüksüne sahip değilseniz, aşağıdakiler ihtiyacınız olanı yapacaktır:

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

Herhangi bir harici kitap gerektirmez ve gün ışığından yararlanma hesabını verir. Görevi bir Calendarnesne olarak çalıştırmak istediğiniz saati ve bir Runnable. Örneğin:

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 zamanlayıcı görevi, herhangi bir GÇ yapmak için tavsiye edilmeyen bir Daemon iş parçacığında çalışır. Bir Kullanıcı iş parçacığı kullanmanız gerekiyorsa, zamanlayıcıyı iptal eden başka bir yöntem eklemeniz gerekecektir.

A kullanmanız gerekiyorsa ScheduledExecutorService, startTimeryöntemi şu şekilde değiştirmeniz yeterlidir :

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

Davranıştan emin değilim, ancak rotadan shutdownNowaşağı inerseniz çağıran bir durdurma yöntemine ihtiyacınız olabilir ScheduledExecutorService, aksi takdirde uygulamanız onu durdurmaya çalıştığınızda takılabilir.


Ne demek istediğini anladım. +1 ve teşekkür ederim. Ancak, Daemon thread (yani, new Timer(runThreadName, true)) kullanmazsak daha iyi olur .
Sage

@Sage endişelenme. Herhangi bir GÇ yapmıyorsanız, bir arka plan programı iş parçacığı iyidir. Bunu yazdığım kullanım senaryosu, bazı günlük temizlik görevlerini gerçekleştirmek için bazı konuları başlatmak için basit bir ateş ve unut sınıfıydı. OP'nin isteğinin gösterebileceği gibi, zamanlayıcı görev dizisinde veritabanı okumaları yapıyorsanız, bir Daemon kullanmamalısınız ve uygulamanızı sonlandırmak için çağırmanız gereken bir tür durdurma yöntemine ihtiyacınız olacaktır. stackoverflow.com/questions/7067578/…
PaddyD

@PaddyD Son bölüm, yani ScheduledExecutorSerive kullanan doğru mu ??? Anonim sınıfın yaratılma şekli sözdizimi açısından doğru görünmüyor. Ayrıca newSingleThreadExecutor () doğru zamanlama yöntemine sahip olmaz mıydı?
FReeze FRanc

6

Quartz Scheduler gibi bir şey kullanmayı düşündünüz mü ? Bu kütüphane, cron benzeri bir ifade (bir göz atın CronScheduleBuilder) kullanarak her gün belirli bir zaman diliminde çalışacak görevleri zamanlamak için bir mekanizmaya sahiptir .

Bazı örnek kod (test edilmemiştir):

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

Önceden biraz daha çalışma var ve iş yürütme kodunuzu yeniden yazmanız gerekebilir, ancak bu, işinizin nasıl çalışmasını istediğiniz konusunda size daha fazla kontrol sağlamalıdır. Ayrıca ihtiyaç duyduğunuzda programı değiştirmek daha kolay olacaktır.


5

Java8:
En iyi yanıttan yükseltme sürümüm:

  1. Boşta iş parçacığına sahip iş parçacığı havuzu nedeniyle Web Uygulama Sunucusunun durmak istemediği durum düzeltildi
  2. Özyineleme olmadan
  3. Görevi özel yerel saatinizle çalıştırın, benim durumumda Belarus, 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
Benzer bir ihtiyacım var. Belirli bir saatte bir gün için görev planlamam gerekiyor. Zamanlanan görev tamamlandığında, belirli bir saatte sonraki gün için görev planlayın. Bu devam etmeli. Sorum, zamanlanmış görevin tamamlandığını veya tamamlanmadığını nasıl öğreneceğim. Planlanan görevin tamamlandığını öğrendiğimde, yalnızca bir sonraki gün için planlama yapabilirim.
amitwdh

2

Benzer bir problemim vardı. Kullanarak bir gün boyunca yürütülmesi gereken bir dizi görevi planlamak zorunda kaldım ScheduledExecutorService. Bu, 3: 30'da başlayan ve diğer tüm görevleri mevcut saatine göre planlayan bir görevle çözüldü . Ve ertesi gün 3: 30'da kendini yeniden planlıyor.

Bu senaryo ile gün ışığından tasarruf artık sorun olmaktan çıkıyor.


2

Basit bir tarih ayrıştırması kullanabilirsiniz, günün saati şimdiden önceyse, yarın başlayalım:

  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

Sadece Victor'un cevabını eklemek için .

Değişkenin (onun durumunda uzun olan midnight) 'den daha büyük olup olmadığını görmek için bir kontrol eklemenizi tavsiye ederim 1440. Öyleyse, atlardım .plusDays(1), aksi takdirde görev yalnızca yarından sonraki gün çalışır.

Bunu basitçe şöyle yaptım:

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

truncatedTo()
Kullanırsanız

1

Aşağıdaki örnek benim için çalışıyor

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

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


1

Görevinizi her gün belirli bir saatte planlamak için aşağıdaki sınıfı kullanabilirsiniz

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
Lütfen modası geçmiş Dateve TimeUnit2019'da kullanmayın
Mark Jeronimus

0

Ya sunucunuz 4: 59'da kapanır ve 5: 01'de geri gelirse? Sanırım sadece koşuyu atlayacak. Zamanlama verilerini bir yerde depolayan Quartz gibi kalıcı bir zamanlayıcıyı tavsiye ederim. Daha sonra bu çalışmanın henüz gerçekleştirilmediğini görecek ve 5: 01'de yapacak.


0

Böyle yazabiliyorsan neden bir durumu karmaşıklaştırıyorsun? (evet -> düşük uyum, kodlanmış -> ama bu bir örnek ve maalesef zorunlu bir yol). Ek bilgi için aşağıdaki kod örneğini okuyun;))

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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.