I have two different tasks, let's call them A and B.
Task A should start immediately (t0) and stop after a fixed time (t1), task B should start after a fixed time (t1) and run until i stop the service.
Both task A and B should do something every x seconds (for convenience, print a string). I know that in Springboot i can achive that using this annotation:
#Scheduled(fixedDelay = 6000)
private void taskA(){
print("A")
}
But i have no clue how to start and stop each tasks after the time window has passed.
I have made a simple scheme to help you understand better.
Thanks
You can schedule a task programatically via org.springframework.scheduling.TaskScheduler.
e.g.
#Autowired
private TaskScheduler taskScheduler;
void scheduleTask(){
final int xSeconds = 2000;
PeriodicTrigger periodicTrigger = new PeriodicTrigger(xSeconds, TimeUnit.SECONDS);
taskScheduler.schedule(
() -> System.out.println("task B"),
periodicTrigger
);
}
This acticle can also be helpful.
You can combine fixedRate with initialDelay annotation.
So taskB runs after an initial delay of 6100 ms.
A --------- B ----- A -------- B ----- A ------>
t(0) t(5900) t(6000) t(1900) t(12000)
#Scheduled(fixedRate = 6000)
private void taskA(){
System.out.println("A");
}
#Scheduled(fixedRate = 6000, initialDelay = 5000)
private void taskB(){
System.out.println("B");
}
The #Scheduled annotation is for stuff that runs forever.
Consider TaskScheduler for the task that must stop and
#Scheduled for the task that should run until you stop the service.
Here is some code:
#Component
#RequiredArgsConstructor
public class Blam
implements
Runnable
{
private int count = 0;
private ScheduledFuture<?> scheduledFuture = null;
private final TaskScheduler taskScheduler;
#Override
public void run()
{
if (count < 6)
{
System.out.printf("%d: blam.taskA\n", count);
++count;
}
else
{
scheduledFuture.cancel(true);
}
}
#PostConstruct
public void postConstruct()
{
scheduledFuture = taskScheduler.scheduleWithFixedDelay(this, 1000);
}
}
#Component
public class Kapow
{
#Scheduled(initialDelay = 6000, fixedDelay = 1000)
public void taskB()
{
System.out.println("Kapow.taskB");
}
}
#RequiredArgsConstructor is a Lombok annotation,
I highly recommend using Lombok.
If you don't use Lombok,
just inject the TashScheduler however you choose.
Related
I want to execute the same task couple of times but it seems that every next invocation of my code does not execute the task immediately, for example it executes after one minute.
Since user has to schedule tasks manually I use ScheduledTaskRegistrar.TaskScheduler.
taskRegistrar.getScheduler().schedule(myTask, new Date());
What could be the reason? User clicked schedule button twice on my fronted application and backend invoked the above schedule method twice as expected. First execution of my task was immediate, second run after two minutes.
UPDATE: taskregistrar config, maybe I didn't configure it at all. my tasks are added as cron tasks on application deployment. But they also must be runnable manually if user wants to trigger it. Below is more or less the whole logic:
#Configuration
#EnableAsync
#EnableScheduling
#Component
#Slf4j
#Generated
#Getter
public class ScheduleTaskService implements SchedulingConfigurer {
#Autowired
private List< MyTask> taskList;
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
taskList.stream().filter(MyTask::isOn).forEach(this::addTaskToScheduler);
}
public void addTaskToScheduler(GwoTask task) {
taskRegistrar.addCronTask(task, task.getCronExpression());
}
public void scheduleImmediateInvocation(MyTask myTask) {
taskRegistrar.getScheduler().schedule(myTask, new Date());
}
}
By referring to the source code of ScheduledTaskRegistrar,
protected void scheduleTasks() {
if (this.taskScheduler == null) {
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
...
If we do not set taskScheduler, Executors.newSingleThreadScheduledExecutor() is used by default. Hence new task will be blocked by processing task.
For your use case in scheduleImmediateInvocation, I recommend to use another thread pool(Probably from Executors) instead as:
It isn't actually a schedule job.
More control on pool size is needed to suit your workload
If you just want to make ScheduledTaskRegistrar execute more concurrently, configure it as:
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// set the desired core pool size
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
this.taskRegistrar = taskRegistrar;
// ...
}
In my spring boot application, There is one scheduler class which execute in every 30 mins and fetch around 20000 records and then insert record one by one in database and then convert that inserted record in XML and send to client. But this process takes too much time to completed 20000 records and records is increasing day by day.
So now, We have to implement asynchronous execution programming in this code so that multiple threads can perform operation instead of one by one records. For example : There are 4 threads and list of item size is 6 then thread_1 will take (0) index object to perform, thread_2 will take (1) index object to perform, thread_3 will take (2) index object to perform, thread_4 will take (3) index object to perform, thread_1 will take (4) index object to perform, thread_2 will take (5) index object to perform
Something like that
For this case, How to implement asynchronous execution
#Service
class ItemService
{
#autowired
private DemoDao dao;
#Scheduled(fixedRate=30000)
public void scheduler(){
try {
List<Item> itemList = dao.getItems();
saveAndSend(itemList);
} catch(Exception e) {
e.printStack();
}
}
public void saveAndSend(List<Item> itemList) throws Exception {
for(int i = 0; i < itemList.size(); i++){
if(itemList.get(i).isDone){
dao.save(itemList.get(i));
int flag = convertInXMLAndSendToTeam(itemList.get(i));
if(flag == 1){
dao.audit(itemList.get(i), "XEQ");
}
}
}
}
}
Please help.
Try putting a name, it works for me like this
#Async("ThreadPoolTaskExecutor")
In SprintBootApplication put the following
#EnableAsync
and then
#Bean("ThreadPoolTaskExecutor")
public TaskExecutor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(30);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("Async-");
executor.setTaskDecorator(new APMTaskDecorator());
return executor;
}
If you use #Async and #Scheduled in same class the async methods are still executed synchronously.
#Async generates a proxy class which encapsulated the original method. So #Async works only if you invoke the method externally. Hence the #Scheduled on the same class is still executed synchronously.
The simpliest solution would be to move the #Scheduled methods to a sperate class.
#Service
public class ItemService {
#Async
public void saveAndSend() {
}
}
#Service
public class ItemSchedulerService {
private final ItemService itemService;
public ItemSchedulerService(ItemService itemService) {
this.itemService = itemService;
}
#Scheduled("...")
public void schedule() {
itemService.saveAndSend();
}
}
I have a scheduler, which triggers at a fixed delay of 5secs.
I am planning to have more than one schedulers, but for now, let's stick to just one scheduler.
Requirement: Based on business condition scheduler's fixedDelay should be changed. **e.g, ** default fixedDelay is 5secs, but it can be 6, 8, 10secs, based on condition.
So, in order to acheive this, I am trying to modify the fixedDelay.
But it's not working for me.
Code:
Interface, with delay methods.
public abstract class DynamicSchedule{
/**
* Delays scheduler
* #param milliseconds - the time to delay scheduler.
*/
abstract void delay(Long milliseconds);
/**
* Decreases delay period
* #param milliseconds - the time to decrease delay period.
*/
abstract void decreaseDelayInterval(Long milliseconds);
/**
* Increases delay period
* #param milliseconds - the time to increase dela period
*/
abstract void increaseDelayInterval(Long milliseconds);
}
Implementating Trigger interface that is located at org.springframework.scheduling in the spring-context project.
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private TaskScheduler taskScheduler;
private ScheduledFuture<?> schedulerFuture;
/**
* milliseconds
*/
private long delayInterval;
public CustomDynamicSchedule(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
#Override
public void increaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
#Override
public void decreaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
#Override
public void delay(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval = delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
configuration:
#Configuration
public class DynamicSchedulerConfig {
#Bean
public CustomDynamicSchedule getDinamicScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.initialize();
return new CustomDynamicSchedule(threadPoolTaskScheduler);
}
}
Test class, to test the usage.
#EnableScheduling
#Component
public class TestSchedulerComponent {
#Autowired
private CustomDynamicSchedule dynamicSchedule;
#Scheduled(fixedDelay = 5000)
public void testMethod() {
dynamicSchedule.delay(1000l);
dynamicSchedule.increaseDelayInterval(9000l);
dynamicSchedule.decreaseDelayInterval(5000l);
}
}
I have took help of https://stackoverflow.com/a/51333059/4770397,
But unfortunately, this code is not working for me.
Scheduler is running at fixedDelay, there is not change in that.
Please help..
Using #Scheduled will only allow to use static schedules. You can use properties to make the schedule configruable like this
#Scheduled(cron = "${yourConfiguration.cronExpression}")
// or
#Scheduled(fixedDelayString = "${yourConfiguration.fixedDelay}")
However the resulting schedule will be fixed once your spring context is initialized (the application is started).
To get fine grained control over a scheduled execution you need implement a custom Trigger - similar to what you already did. Together with the to be executed task, this trigger can be registered by implementing SchedulingConfigurer in your #Configuration class using ScheduledTaskRegistrar.addTriggerTask:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
taskRegistrar.addTriggerTask(() -> myTask().work(), myTrigger());
}
#Bean(destroyMethod="shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(42);
}
#Bean
public CustomDynamicSchedule myTrigger() {
new CustomDynamicSchedule();
}
#Bean
public MyTask myTask() {
return new MyTask();
}
}
But don't do any registration of a task in the CustomDynamicSchedule just use it to compute the next execution time:
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private long delayInterval;
#Override
public synchronized void increaseDelayInterval(Long delay) {
this.delayInterval += delay;
}
#Override
public synchronized void decreaseDelayInterval(Long delay) {
this.delayInterval += delay;
}
#Override
public synchronized void delay(Long delay) {
this.delayInterval = delay;
}
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
But remember to make CustomDynamicSchedule thread safe as it will be created as singleton by spring and might be accessed by multiple threads in parallel.
Spring's #Scheduled annotation does not provide this support.
This is my preferred implementation of a similar feature using a Queue-based solution which allows flexibility of timing and very robust implementation of this scheduler functionality.
This is the pipeline-
Cron Maintainer and Publisher- For every task, there is an affiliated cron and a single-threaded executor service which is responsible for publishing messages to the Queue as per the cron. The task-cron mappings are persisted in the database and are initialized during the startup. Also, we have an API exposed to update cron for a task at runtime.
We simply shut down the old scheduled executor service and create a one whenever we trigger a change in the cron via our API. Also, we update the same in the database.
Queue- Used for storing messages published by the publisher.
Scheduler- This is where the business logic of the schedulers reside. A listener on the Queue(Kafka, in our case) listens for the incoming messages and invokes the corresponding scheduler task in a new thread whenever it receives a message for the same.
There are various advantages to this approach. This decouples the scheduler from the schedule management task. Now, the scheduler can focus on business logic alone. Also, we can write as many schedulers as we want, all listening to the same queue and acting accordingly.
With annotation you can do it only by aproximation by finding a common denominator and poll it. I will show you later. If you want a real dynamic solution you can not use annotations but you can use programmatic configuration. The positive of this solution is that you can change the execution period even in runtime! Here is an example on how to do that:
public initializeDynamicScheduledTAsk (ThreadPoolTaskScheduler scheduler,Date start,long executionPeriod) {
scheduler.schedule(
new ScheduledTask(),
new Date(startTime),period
);
}
class ScheduledTask implements Runnable{
#Override
public void run() {
// my scheduled logic here
}
}
There is a way to cheat and actually do something with annotations. But you can do that only if precision is not important. What does it mean precision. If you know that you want to start it every 5 seconds but 100ms more or less is not important. If you know that you need to start every 5-6-8 or 10 seconds you can configure one job that is executing every second and check within one if statement how long has it passed since the previous execution. It is very lame, but it works :) as long as you don't need up to millisecond precision. Here is an example:
public class SemiDynamicScheduledService {
private Long lastExecution;
#Value(#{yourDynamicConfiguration})
private int executeEveryInMS
#Scheduled(fixedDelay=1000)
public semiDynamicScheduledMethod() {
if (System.currentTimeMS() - lastExecution>executeEveryInMS) {
lastExecution = System.currentTimeMS();
// put your processing logic here
}
}
}
I is a bit lame but will do the job for simple cases.
I have a scheduler, which triggers at a fixed delay of 5secs.
I am planning to have more than one schedulers, but for now, let's stick to just one scheduler.
Requirement: Based on business condition scheduler's fixedDelay should be changed. **e.g, ** default fixedDelay is 5secs, but it can be 6, 8, 10secs, based on condition.
So, in order to acheive this, I am trying to modify the fixedDelay.
But it's not working for me.
Code:
Interface, with delay methods.
public abstract class DynamicSchedule{
/**
* Delays scheduler
* #param milliseconds - the time to delay scheduler.
*/
abstract void delay(Long milliseconds);
/**
* Decreases delay period
* #param milliseconds - the time to decrease delay period.
*/
abstract void decreaseDelayInterval(Long milliseconds);
/**
* Increases delay period
* #param milliseconds - the time to increase dela period
*/
abstract void increaseDelayInterval(Long milliseconds);
}
Implementating Trigger interface that is located at org.springframework.scheduling in the spring-context project.
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private TaskScheduler taskScheduler;
private ScheduledFuture<?> schedulerFuture;
/**
* milliseconds
*/
private long delayInterval;
public CustomDynamicSchedule(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
#Override
public void increaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
#Override
public void decreaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
#Override
public void delay(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval = delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
configuration:
#Configuration
public class DynamicSchedulerConfig {
#Bean
public CustomDynamicSchedule getDinamicScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.initialize();
return new CustomDynamicSchedule(threadPoolTaskScheduler);
}
}
Test class, to test the usage.
#EnableScheduling
#Component
public class TestSchedulerComponent {
#Autowired
private CustomDynamicSchedule dynamicSchedule;
#Scheduled(fixedDelay = 5000)
public void testMethod() {
dynamicSchedule.delay(1000l);
dynamicSchedule.increaseDelayInterval(9000l);
dynamicSchedule.decreaseDelayInterval(5000l);
}
}
I have took help of https://stackoverflow.com/a/51333059/4770397,
But unfortunately, this code is not working for me.
Scheduler is running at fixedDelay, there is not change in that.
Please help..
Using #Scheduled will only allow to use static schedules. You can use properties to make the schedule configruable like this
#Scheduled(cron = "${yourConfiguration.cronExpression}")
// or
#Scheduled(fixedDelayString = "${yourConfiguration.fixedDelay}")
However the resulting schedule will be fixed once your spring context is initialized (the application is started).
To get fine grained control over a scheduled execution you need implement a custom Trigger - similar to what you already did. Together with the to be executed task, this trigger can be registered by implementing SchedulingConfigurer in your #Configuration class using ScheduledTaskRegistrar.addTriggerTask:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
taskRegistrar.addTriggerTask(() -> myTask().work(), myTrigger());
}
#Bean(destroyMethod="shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(42);
}
#Bean
public CustomDynamicSchedule myTrigger() {
new CustomDynamicSchedule();
}
#Bean
public MyTask myTask() {
return new MyTask();
}
}
But don't do any registration of a task in the CustomDynamicSchedule just use it to compute the next execution time:
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private long delayInterval;
#Override
public synchronized void increaseDelayInterval(Long delay) {
this.delayInterval += delay;
}
#Override
public synchronized void decreaseDelayInterval(Long delay) {
this.delayInterval += delay;
}
#Override
public synchronized void delay(Long delay) {
this.delayInterval = delay;
}
#Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
But remember to make CustomDynamicSchedule thread safe as it will be created as singleton by spring and might be accessed by multiple threads in parallel.
Spring's #Scheduled annotation does not provide this support.
This is my preferred implementation of a similar feature using a Queue-based solution which allows flexibility of timing and very robust implementation of this scheduler functionality.
This is the pipeline-
Cron Maintainer and Publisher- For every task, there is an affiliated cron and a single-threaded executor service which is responsible for publishing messages to the Queue as per the cron. The task-cron mappings are persisted in the database and are initialized during the startup. Also, we have an API exposed to update cron for a task at runtime.
We simply shut down the old scheduled executor service and create a one whenever we trigger a change in the cron via our API. Also, we update the same in the database.
Queue- Used for storing messages published by the publisher.
Scheduler- This is where the business logic of the schedulers reside. A listener on the Queue(Kafka, in our case) listens for the incoming messages and invokes the corresponding scheduler task in a new thread whenever it receives a message for the same.
There are various advantages to this approach. This decouples the scheduler from the schedule management task. Now, the scheduler can focus on business logic alone. Also, we can write as many schedulers as we want, all listening to the same queue and acting accordingly.
With annotation you can do it only by aproximation by finding a common denominator and poll it. I will show you later. If you want a real dynamic solution you can not use annotations but you can use programmatic configuration. The positive of this solution is that you can change the execution period even in runtime! Here is an example on how to do that:
public initializeDynamicScheduledTAsk (ThreadPoolTaskScheduler scheduler,Date start,long executionPeriod) {
scheduler.schedule(
new ScheduledTask(),
new Date(startTime),period
);
}
class ScheduledTask implements Runnable{
#Override
public void run() {
// my scheduled logic here
}
}
There is a way to cheat and actually do something with annotations. But you can do that only if precision is not important. What does it mean precision. If you know that you want to start it every 5 seconds but 100ms more or less is not important. If you know that you need to start every 5-6-8 or 10 seconds you can configure one job that is executing every second and check within one if statement how long has it passed since the previous execution. It is very lame, but it works :) as long as you don't need up to millisecond precision. Here is an example:
public class SemiDynamicScheduledService {
private Long lastExecution;
#Value(#{yourDynamicConfiguration})
private int executeEveryInMS
#Scheduled(fixedDelay=1000)
public semiDynamicScheduledMethod() {
if (System.currentTimeMS() - lastExecution>executeEveryInMS) {
lastExecution = System.currentTimeMS();
// put your processing logic here
}
}
}
I is a bit lame but will do the job for simple cases.
I'm trying to implement a system in server that will do some updates on database on a ragular basis.
Here: Spawning threads in a JSF managed bean for scheduled tasks using a timer
and in some other similar questions, I saw that BalusC strongly recommended to use Stateless Beans, if not possible SchedulerExecuterService rather than Timer.
Here is my situation. I need a JSF page in which I can configure the schedule interval. i.e. I can change its rule from run once in every 5 min to run once in 10 min
First, I tried to use #Schedule annotation and it was great. However, I couldn't find a way to change interval with that. First question, is it possible to change it dynamically like I told above?
I am currently using SchedulerExecutorService which is called from #PostConstruct of a Stateless Bean.
Second question, is the Timer BalusC strongly recommended not to use is the TimerService of EJB?
Third Question, I liked the properties of timerService which is:
using scheduleExpression and timerConfig.
Are there any similar things for ScheduledExecutorService?
Additional Question: Am I on right track? Can the thing that I am trying to pull be done in a better way?
I think #Schedule is used only for fixed cron-like timers, where the EJB container deploys a timer at EJB startup. You obviously need more dynamic scheduling connected with a JSF page.
If you are running on a full Java EE 6 profile, why not use the TimerService with a Stateless Session EJB like this:
#Stateless
public class JobSchedulerBean {
#Resource
private TimerService timerService;
// #PostConstruct
public void initTimer() {
// set initial timer
ScheduleExpression sch = new ScheduleExpression();
// set cron expression into sch
timerService.createCalendarTimer(sch, new TimerConfig("myTimer", false));
}
public void rescheduleTimer(int interval) {
// get timer from timer service
for (Timer timer : timerService.getTimers()) {
if (timer != null && timer.getInfo().equals("myTimer")) {
timer.cancel();
}
}
// schedule new timer, like in initTimer() method
}
#Timeout
public void timeout(Timer timer) {
// do the job
}
}
EDIT:
#ManagedBean(eager=true)
#ApplicationScoped
public class JobRunner {
private ScheduledExecutorService scheduler;
private static final int POOL_SIZE = 1;
ScheduledFuture<?> runHandle;
#PostConstruct
public void init() {
scheduler = Executors.newScheduledThreadPool(POOL_SIZE);
// set initial expiry to 5 minutes after 5 minutes delay
runHandle = scheduler.scheduleAtFixedRate(new MyJob(), 5, 5, TimeUnit.MINUTES);
}
#PreDestroy
public void destroy() {
scheduler.shutdownNow();
}
public void reschedule(int newDelay) {
// cancel old timer, but do not interrupt it
runHandle.cancel(false);
runHandle = scheduler.scheduleAtFixedRate(new MyJob(), newDelay, newDelay, TimeUnit.MINUTES);
}
}
public class MyJob implements Runnable {
public void run() {
// do the job
}
}