Как запланировать периодическое задание на Java?

Мне нужно запланировать задачу для выполнения в фиксированный интервал времени. Как я могу сделать это с поддержкой длинных интервалов (например, каждые 8 ​​часов)?

Я сейчас пользуюсь java.util.Timer.scheduleAtFixedRate, Есть ли java.util.Timer.scheduleAtFixedRate поддерживать длинные промежутки времени?

14 ответов

Решение

Используйте ScheduledExecutorService:

 private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
 scheduler.scheduleAtFixedRate(yourRunnable, 8, 8, TimeUnit.HOURS);

Вы должны взглянуть на Quartz - это Java-фреймворк, который работает с выпусками EE и SE и позволяет определять задания для выполнения в определенное время.

Попробуйте так ->

Сначала создайте класс TimeTask, который запускает вашу задачу, он выглядит так:

public class CustomTask extends TimerTask  {

   public CustomTask(){

     //Constructor

   }

   public void run() {
       try {

         // Your task process

       } catch (Exception ex) {
           System.out.println("error running thread " + ex.getMessage());
       }
    }
}

затем в основном классе вы создаете экземпляр задачи и периодически запускаете ее к указанной дате:

 public void runTask() {

        Calendar calendar = Calendar.getInstance();
        calendar.set(
           Calendar.DAY_OF_WEEK,
           Calendar.MONDAY
        );
        calendar.set(Calendar.HOUR_OF_DAY, 15);
        calendar.set(Calendar.MINUTE, 40);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);



        Timer time = new Timer(); // Instantiate Timer Object

        // Start running the task on Monday at 15:40:00, period is set to 8 hours
        // if you want to run the task immediately, set the 2nd parameter to 0
        time.schedule(new CustomTask(), calendar.getTime(), TimeUnit.HOURS.toMillis(8));
}

Используйте Google Guava AbstractScheduledService как указано ниже:

public class ScheduledExecutor extends AbstractScheduledService
{
   @Override
   protected void runOneIteration() throws Exception
   {
      System.out.println("Executing....");
   }

   @Override
   protected Scheduler scheduler()
   {
        return Scheduler.newFixedRateSchedule(0, 3, TimeUnit.SECONDS);
   }

   @Override
   protected void startUp()
   {
       System.out.println("StartUp Activity....");
   }


   @Override
   protected void shutDown()
   {
       System.out.println("Shutdown Activity...");
   }

   public static void main(String[] args) throws InterruptedException
   {
       ScheduledExecutor se = new ScheduledExecutor();
       se.startAsync();
       Thread.sleep(15000);
       se.stopAsync();
   }

}

Если у вас есть больше подобных сервисов, тогда регистрация всех сервисов в ServiceManager будет хорошей, так как все сервисы можно запускать и останавливать вместе. Читайте здесь для получения дополнительной информации о ServiceManager.

Если вы хотите придерживаться java.util.Timer, вы можете использовать его для планирования через большие промежутки времени. Вы просто проходите период, за который стреляете. Проверьте документацию здесь.

Делай что-нибудь каждую секунду

Timer timer = new Timer();
timer.schedule(new TimerTask() {
       @Override
       public void run() {
           //code
       }
    }, 0, 1000);
Here are a few ways to run schedule task periodically:
1. Scheduler Task

import java.util.TimerTask;
import java.util.Date;
public class ScheduledTask extends TimerTask { // Create a class extends with TimerTask
Date now; 
public void run() { //Write your code in public void run() method that you want to execute periodically.
now = new Date(); // initialize date
System.out.println("Time is :" + now); // Display current time
}
}

2. Run Scheduler Task
import java.util.Timer;
public class SchedulerMain {
public static void main(String args[]) throws InterruptedException {
Timer time = new Timer(); // Instantiate Timer Object
ScheduledTask st = new ScheduledTask(); // Instantiate SheduledTask class
time.schedule(st, 0, 1000); // Create Repetitively task for every 1 secs
//for demo only.
for (int i = 0; i <= 5; i++) {
System.out.println("Execution in Main Thread...." + i);
Thread.sleep(2000);
if (i == 5) {
System.out.println("Application Terminates");
System.exit(0);
}
}
}
}

Reference https://www.mkyong.com/java/how-to-run-a-task-periodically-in-java/

Если ваше приложение уже использует Spring Framework, у вас есть встроенное планирование

Вы также можете использовать JobRunr, простой в использовании планировщик Java с открытым исходным кодом .

Чтобы запланировать задание каждые 8 ​​часов с помощью JobRunr, вы должны использовать следующий код:

      BackgroundJob.scheduleRecurrently(Duration.ofHours(8), () -> yourService.methodToRunEvery8Hours());

Если вы используете Spring Boot, Micronaut или Quarkus, вы также можете использовать@Recurringаннотация:

      
public class YourService {

    @Recurring(interval="PT8H")
    public void methodToRunEvery8Hours() {
        // your business logic
    }

}

JobRunr также поставляется со встроенной панелью управления, которая позволяет вам следить за тем, как выполняются ваши задания.

Я использую функцию Spring Framework. (jar-контекстная зависимость jav или maven).

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;


@Component
public class ScheduledTaskRunner {

    @Autowired
    @Qualifier("TempFilesCleanerExecution")
    private ScheduledTask tempDataCleanerExecution;

    @Scheduled(fixedDelay = TempFilesCleanerExecution.INTERVAL_TO_RUN_TMP_CLEAN_MS /* 1000 */)
    public void performCleanTempData() {
        tempDataCleanerExecution.execute();
    }

}

ScheduledTask - это мой собственный интерфейс с моим пользовательским методом execute, который я называю своей запланированной задачей.

Вы пробовали Spring Scheduler, используя аннотации?

@Scheduled(cron = "0 0 0/8 ? * * *")
public void scheduledMethodNoReturnValue(){
    //body can be another method call which returns some value.
}

Вы можете сделать это и с XML.

 <task:scheduled-tasks>
   <task:scheduled ref = "reference" method = "methodName" cron = "<cron expression here> -or- ${<cron expression from property files>}"
 <task:scheduled-tasks>

Если вам нужно запустить запланированное задание в режиме потока.
Класс ScheduledThreadPoolExecutor рекомендуется.

public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService

ThreadPoolExecutor, который может дополнительно запланировать выполнение команд после заданной задержки или периодическое выполнение. Этот класс предпочтительнее, чем Timer, когда требуется несколько рабочих потоков или когда требуется дополнительная гибкость или возможности ThreadPoolExecutor (который расширяет этот класс). Задержанные задачи выполняются не раньше, чем они включены, но без каких-либо гарантий в реальном времени о том, когда после их включения они начнутся. Задачи, запланированные на одно и то же время выполнения, включаются в порядке поступления в порядке поступления (FIFO).

Когда переданная задача отменяется до ее запуска, выполнение подавляется. По умолчанию такая отмененная задача не удаляется автоматически из рабочей очереди до тех пор, пока не истечет ее задержка. Хотя это позволяет проводить дальнейшую проверку и мониторинг, оно также может привести к неограниченному сохранению отмененных задач. Чтобы избежать этого, используйте setRemoveOnCancelPolicy(логическое значение), чтобы немедленно удалять задачи из рабочей очереди во время отмены.

Последовательное выполнение периодической задачи, запланированное с помощью scheduleAtFixedRate или scheduleWithFixedDelay, не перекрывается. В то время как разные исполнения могут выполняться разными потоками, эффекты предыдущих выполнений происходят раньше, чем эффекты последующих.

Хотя этот класс наследуется от ThreadPoolExecutor, некоторые из унаследованных методов настройки для него бесполезны. В частности, поскольку он действует как пул фиксированного размера, использующий потоки corePoolSize и неограниченную очередь, изменения в MaximumPoolSize не дают никакого полезного эффекта. Кроме того, почти никогда не рекомендуется устанавливать значение corePoolSize равным нулю или использовать allowCoreThreadTimeOut, потому что это может оставить пул без потоков для обработки задач, как только они получат право на запуск.

Мой сервлет содержит это как код, как сохранить это в планировщике, если пользователь нажимает принять

if(bt.equals("accept")) {
    ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1);
    String lat=request.getParameter("latlocation");
    String lng=request.getParameter("lnglocation");
    requestingclass.updatelocation(lat,lng);
}

Eсть ScheduledFuture class в java.util.concurrent, это может вам помочь.

Другие вопросы по тегам