I use a Timer and TimerTasks to schedule some tasks to be execuded. Some of the tasks must be rescheduled. I need a mechanism to “name” tasks (e.g. by a String ID) so I can reschedule them or remove them and schedule them at a new time.
The project that I’m working on is a Flight Display System. Every flight when inserted to the DB has a scheduled arrival and departure time. So I use one timer task to update airport displays when a flight must be shown and another one to hide it.
Everything is fine until there is a change in the flight time. The user updates the time in the DB but then I need to reschedule the display update times. This is the point where I need your help.
What do you think about a simple HashMap<UUID, TimerTask> tasks. You could find any Task by the given ID, cancel it, or reschedule it later.
update
public class TimerThingy{
HashMap<UUID,TimerTask> tasks = new HashMap<UUID,TimerTask>();
Timer timer = new Timer();
public UUID createAndStartTimer(final Runnable task, Date when){
TimerTask timerTask = new TimerTask(){
public void run(){
task.run();
}
}
timer.schedule(TimerTask timerTask, Date when);
UUID id = UUID.randomUUID();
tasks.put(id, t);
return id;
}
public void cancelTimer(UUID id){
tasks.get(id).cancel();
}
}
Well this is some kind of easiest Scheduler with an ID to cancel. I think you may use something else as ID, because you may to find the correct Task to cancel. But thats up to you..
//You can create a map where you store your tasks, indexed by the id.
Map<String,TimerTask> tasks = new HashMap<String,TimerTask>();
You uses a function to generate your named tasks:
public TimerTask createTask(String name, final Runnable r){
TimerTask task = new TimerTask(){
public void run(){
r.run();
}
}
//here, you save it to the HashMap
tasks.put(name, task);
return task;
}
// update airport displays when a flight must be shown and another to hide it.
Now, to create a task, you create the runnable, like you used to, and creates the name you'd want it to have, for example fligthnumer-show, or flightnumer-hide, and then call that function to create the task.
Runnable r= ... //whatever you does here
String name = "1234-show";
TimerTask task = createTask( name, r);
Now, you can schedule the task,or do whatever you need. besides, your task is saved, so, if you need it again, to cancel it, or to schedule it again, you just need to retrieve it from the hashmap, calling it for its name:
TimerTask task = tasks.get("1234-show");
In this example, it is not really useful, but in your real application, if you are, for instance, creating task dinamically, is easy to build a dynamic list of tasks. Say you have to schedule a task to show the info or a new flight, that probably you already did the day before, or probably is a new one. You can check if there is a task already, and if it is, you can use it, otherwise you crete it and save it.
//say you have flight number in a var called flightNumber, and you are building a "show" task
String name= flightNumber+"show";
TimerTask task = tasks.get(name); //if the task is found, you can use it
//instead, f there is not such task, null will be returned, in that case, you create it.
if (null== task) {
//do al the required stuff, like get the runnable ready, and create the task
task = createTask( name, r);
}
//so here, you can do whatever you need with the task
Related
I have a custom Timer Task that executes once after X seconds in a controller... The scenario which I encountered yesterday happens when I schedule my Timer Task and, instantly, I schedule another time and a third time. Every time I schedule, I create a custom object from a class A and assign it to this timer task (so that it does some work in the run method afterwards).
The strange scenario comes when the custom timer task is executed because itś like I have assigned the third object to the three custom timer task object... Instead of retaining each custom timer task object its corresponding instance of A... I will investigate meanwhile the API...
#RequestMapping(value = "execute", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_VALUE})
#ResponseBody
public void executeTimerTask(#RequestParam("task") String task) {
new java.util.Timer().schedule(new java.util.TimerTask() {
#Override
public void run() {
System.out.println("task: " + task);
}
}, 10 * 1000);
}
This would be more or less a copy of what I have before creating the custom timer task... If I execute quickly and hit this endpoint three times (before 10 seconds), when the timer task is executed what it's going to be printed is the value from the third endpoint execution. What I want is a way of retaining each value when the task is executed...
I'm trying to solve a problem similar to downloading new mails from mail servers by mail client. I have a task, which is performed regularly (next iteration is 10 minutes after the last one ends for example) but there is also a possibility to run the task manually.
When I am trying to run the job manually and job is not running at this moment (is appointed for later), I cancel the appointment and schedule it for now. When the job is already running I do not cancel it, but wait until it finishes and run it again. But only one task can wait this way.
My problem is that I do not know how to synchronize the jobs to make it thread safe and make sure that job never runs twice at the same time.
To make it more clear. The main problem is that simple asking if the job is running and deciding based on what I get is not enough, because between the question and action the situation can change. It is a short span but the probability is not zero. And the same problem is with deciding if I should run the job again at the end of his run. If my decision is based on the value of some variable or some other if clause, then between testing its value and performing some action, some other thread can change it and I can end up with two scheduled jobs or none at all.
Have you considered using a DelayQueue?
To make your job run now you just need to persuade it to return 0 form getDelay(TimeUnit unit).
The main way to do that check you are telling about is to check, to lock and after that to repeat the same check:
public class OneQueuedThread extends Thread {
static int numberRunning =0;
public void run() {
if (numberRunning<2) {
synchronized (OneQueuedThread.class){
if (numberRunning<2) {
numberRunning++;
// ---------------your process runs here
numberRunning--;
}
}
}
}
}
So, only one attempt to run the thread while it is already running will wait until the end of the running thread and start after it.
As for scheduling, let's use the TimerTask features:
public class ScheduledTask extends TimerTask {
ScheduledTask instance;
/**
* this constructor is to be used for manual launching
*/
public void ScheduledTask(){
if (instance == null){
instance = this;
} else {
instance.cancel();
}
instance.run();
}
/**
* This constructor is to be used for scheduled launching
* #param deltaTime
*/
public ScheduledTask(long deltaTime){
instance = this;
Timer timer = new Timer();
timer.schedule(instance, deltaTime);
}
public void run() {
OneQueuedThread currentTread;
currentTread = new OneQueuedThread();
currentTread.start();
}
}
How do I run a specific set of instructions inside the TimerTask continuously without delay for a set amount of time ? Below are the codes I am attempting to implement the above.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println("Test started at: " + new Date());
// Do something continuously without delay
System.out.println("Test finished at: " + new Date());
}
}, 0);
The second parameter to the schedule method is the time to begin the timer task (or delay relative to now), not the length of time that the timer will execute for.
It's not completely clear from your question but I'm assuming you want the task to start and stop at particular times (or delays relative to now) in the future. If so, the way I would approach this is to create a Thread that does the task you need. Since a TimerTask is a Runnable that is executed as a Thread once the Timer starts it, you can just use an instance of that TimerTask. Ensure that Runnable contains a settable field like running. In that Thread, run your task in a while loop like this:
public void run() {
while(running) { /* do my task */ }
}
Then, use one Timer to schedule the Runnable to start at the time you need. Use another Timer to set the running parameter of the same Thread to false at the time you want it to stop. The running parameter should be volatile to ensure that changes to it from the second timer Thread are seen by the first timer Thread immediately. So it would look something like this (not tested):
class StoppableTimerTask extends TimerTask {
private volatile boolean running = true;
public void stopRunning() { this.running = false; }
public void run() {
while(running) { /* do my task */ }
}
}
final StoppableTimerTask task = new StoppableTimerTask();
timer.schedule(task, startTime);
timer.schedule(new TimerTask() {
public void run() {
task.stopRunning();
}
}, stopTime);
Depending on what your "something" is, you may also want to look into Thread interrupts. For example, if it is doing blocking IO, your code won't loop and check the running value until the blocking IO completes. Interrupting the thread (may) cause that to happen. See http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupt--. This may or may not work, and it can be tricky to get right, so if you need this Thread to exit as close to the desired time as possible, prefer running blocking I/O and similar operations with smaller timeouts so that the thread can check whether it should continue to run more often.
UPDATE: As per the comment indicating that the task should start right away, it becomes even simpler. The initial task doesn't even need to extend TimerTask -- it can just be a regular Thread that is started immediately. The timer is only needed to stop it at the specified future time.
I am running a scheduled task in the web application using the java SingleThreadScheduledExecutor
The problem I have is - How do I identify whether the scheduler is still running and has not crashed?
Is there a better way of doing it rather than having another scheduler to check this particular scheduler
there is actually a way to check
public class TaskSchedulerService{
private final ThreadPoolTaskScheduler taskScheduler; //initialize it here or in constructor
private Map<String,ScheduledFuture<?>> scheduleMap = new ConcurrentHashMap<>();
public TaskSchedulerServiceImpl() {
this.schedulerName = schedulerName;
taskScheduler.initialize();
}
public boolean isScheduled(String taskId) {
final ScheduledFuture<?> exits = scheduledTasks.get(taskId);
return exits != null && exits.isDone();
}
public ScheduledFuture<?> schedule(String taskId, Runnable task, Date date) {
ScheduledFuture<?> scheduled = scheduleMap.get(taskId);
if (scheduled==null ) {
ScheduledFuture<?> future = taskScheduler.schedule(task, date);
scheduleMap.put(taskId, future);
return future;
} else {
// log it is already scheduled
return scheduled;
}
}
i know it is too late but i hope others can get benefit from it
The logic behind the implementation is whenever you are trying to schedule a task, you will have to add it to the map with the taskId as well, in this case it is better to find any task if exists in MAP or if needed remove it as well as checking if that task is done or not
The answer depends on what your scheduler does really. For instance, you can produce a file or update a field in a db or such thing that can be checked and the time interval (from now to last update) can be calculated. In your case, if the time interval of file creation or db updated is more than half an hour this means the job did stop. But notice that scheduled jobs are meant to last forever like love.
In my java web application, I want to schedule a task.
I have searched the web alot and couldn't find a suitable scheduler for my case. In the application I have different types of users. For a specific user type, I want to schedule a task.
By the time a critical action is taken by a user:
I want to send an email to that specific user and after 15 minutes
I want to send another email and after 30 minutes
I want to send another email and shut down the scheduler.
I know when the users take critical actions and how to send email but I don't have much experience about scheduling.
Can anyone help me for the case?
Why don't you use a ScheduledExecutor?
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html
It has a method schedule which allows you to schedule whatever task you want (you pass a runnable). So basically, for each user you schedule a task of sending an e-mail and scheduling another task.
import static java.util.concurrent.TimeUnit.*;
class Task implements Runnable {
private final User user;
private final int rep;
private final ScheduledExecutorService scheduler;
public Task(User user, int rep, ScheduledExecutorService scheduler) {
this.user = user;
this.rep = rep;
this.scheduler = scheduler;
}
public void run() {
// send an e-mail to user
if (rep > 0)
scheduler.schedule(new Task(user, rep - 1, scheduler), 15, MINUTES);
}
}
class Example {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void sendEmails() {
// foreach user
scheduler.submit(new Task(user, 3, scheduler));
}
}
You might want to use a scheduled thread pool with more than one thread.
Use Quartz Scheduler to schedule a task
Steps Required -
1) Quartz job
public class HelloJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello Quartz!");
}
}
2) Creating a trigger - CronTrigger – Run every 30 seconds
CronTrigger trigger = new CronTrigger();
trigger.setName("dummyTriggerName");
trigger.setCronExpression("0/30 * * * * ?");
3) Creating a scheduler
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
Here's a tutorial on how to use Java Timers:
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
You can create multiple Timer tasks in sequence to fufill your objective.
Example
Code Quote:
import java.util.Timer;
import java.util.TimerTask;
/**
* Simple demo that uses java.util.Timer to schedule a task
* to execute once 5 seconds have passed.
*/
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time's up!%n");
timer.cancel(); //Terminate the timer thread
}
}
public static void main(String args[]) {
new Reminder(5);
System.out.format("Task scheduled.%n");
}
}
You can also use JobRunr, an easy to use and open-source Java Scheduler.
To schedule a Job after 15 minutes using JobRunr, you would use the following code:
JobId firstEmailJobId = BackgroundJob.enqueue(() -> yourService.sendFirstEmail());
JobId secondEmailJobId = BackgroundJob.schedule(Instant.now().plus(15, minutes), () -> yourService.sendSecondEmail());
You can then repeat these steps for the other 2 emails. If you want to cancel sending these emails (e.g. when the user took action), you can easily delete these jobs again by means of the JobId (of course only if the job has not executed yet)
JobRunr also comes with automatic retries (e.g. your mailserver or sendgrid is down) and an embedded dashboard that allows you to follow-up on how your jobs are doing.
I would recommend you to take a look at the quartz scheduling API http://quartz-scheduler.org/
I have used it in several projects so far and it is really easy to setup and configure new jobs in. It supports cron based triggers or simpletriggers so you can either calculate the times for the scheduled events in your java code or you can simply pass it a cron string.
Another advantage is that its really easy to configure with spring.