I have a ScheduledExecutorService that times a few different task periodically with scheduleAtFixedRate(Runnable, INIT_DELAY, ACTION_DELAY, TimeUnit.SECONDS);
I also have a different Runnable that I'm using with this scheduler.
the problem starts when I want to remove one of the tasks from the scheduler.
Is there a way to do this?
Am I doing the right thing using one scheduler for different tasks?
What is the best way to implement this?
Simply cancel the future returned by scheduledAtFixedRate():
// Create the scheduler
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// Create the task to execute
Runnable r = new Runnable() {
#Override
public void run() {
System.out.println("Hello");
}
};
// Schedule the task such that it will be executed every second
ScheduledFuture<?> scheduledFuture =
scheduledExecutorService.scheduleAtFixedRate(r, 1L, 1L, TimeUnit.SECONDS);
// Wait 5 seconds
Thread.sleep(5000L);
// Cancel the task
scheduledFuture.cancel(false);
Another thing to note is that cancel does not remove the task from scheduler. All it ensures is that isDone method always return true. This may lead to memory leaks if you keep adding such tasks. For e.g.: if you start a task based on some client activity or UI button click, repeat it n-times and exit. If that button is clicked too many times, you might end up with big pool of threads that cannot be garbage collected as scheduler still has a reference.
You may want to use setRemoveOnCancelPolicy(true) in ScheduledThreadPoolExecutor class available in Java 7 onwards. For backward compatibility, default is set to false.
If your ScheduledExecutorService instance extends ThreadPoolExecutor (e.g. ScheduledThreadPoolExecutor), you could use remove(Runnable) (but see the note in its javadoc: "It may fail to remove tasks that have been converted into other forms before being placed on the internal queue.") or purge().
Related
I created a simple task, to run every two minutes, that I want to stop once a boolean becomes true.
ScheduledExecutorService scheduledxecutor = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> scheduledFuture = scheduledExecutor.scheduleAtFixedRate(drawRunnable , 0, 2, TimeUnit.MINUTES);
I've been lurking around stackoverflow and I basically found that I need to use either scheduledFuture.cancel(false) or scheduledExecutor.shutdown().
Which one should I use?
scheduledExecutor.shutdown() is the better choice b'coz it gracefully starts the shutdown of all the tasks submitted whereas scheduledFuture.cancel(false) only deals with that particular task only.
ExecutorService.shutdown() Java Doc
Future.cancel(boolean) Java
Doc
If the executor service has no tasks, it remains still alive and is ready to be used again. Some resources remain blocked. If you use the executor for this single task only, then better is to use scheduledExecutor.shutdown(). It will wait until the current tasks are completed and will not start new ones. So it is safe to call it even if the task is running at the moment.
But if you add some more tasks to this executor service, it is better to cancel a particular task only. Then you will be sure that you don't cancel any other tasks.
What im trying to do is : Pressing one button change simple value. If value remains unchanged for 3 sec, i wanna execute my method. So i need a single thread which would start(and kill all others) on every button click. I know
Executor executor = Executors.newSingleThreadScheduledExecutor();
but it can't have a delay. What would be the best practice to do this ?
You can simply use the old Thread class or the Runnable interface: start the thread as soon as the button is clicked, execute Thread.sleep(3000) as first instruction, then check if the value is unchanged.
Before starting the thread check if another thread already exists and, if any, call interrupt() on it and handle the InterruptedException to gracefully terminate it.
If you want to use the newer concurrent API, note that Executors.newSingleThreadScheduledExecutor() returns a ScheduledExecutorService (not a simple Executor) and it allows starting a thread with a delay as the name implies. Check the Javadoc.
Either you can go with simple Thread start-stop/interrupt thing or you can use API's like ScheduledExecutorService.
An example of how to do with ScheduledExecutorService is below
//Start as many threads as you want upon button click... (since you said i want to kill all other threads, so i assume you want to start some threads soon upon button click)
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
service.schedule(new Thread(), 0, TimeUnit.SECONDS);
service.schedule(new Thread(), 0, TimeUnit.SECONDS);
service.schedule(new Thread(), 0, TimeUnit.SECONDS);
//Start single thread after 3 seconds.
ScheduledExecutorService serviceCheck = Executors.newScheduledThreadPool(3);
serviceCheck.schedule(new Thread(), 3, TimeUnit.SECONDS);
//In this thread created using "serviceCheck", check with value has not changed then use `service.shutdownNow();` to shutdown all previously started threads and then do whatever you want.
I have the following requirement.
I am trying to build a simulator that will generate load on a system for the purpose of load testing. I want threads to start every X milliseconds, each of which will kick off a task that takes Y milliseconds, with Y being maybe 2 or 3 orders of magnitude > X.
I had thought I could use ScheduledExecutorService.scheduleAtFixedRate(). It hasn't worked. I see the following javadoc comment which explains why:
If any execution of this task takes longer than its period, then
subsequent executions may start late, but will not concurrently
execute.
Concurrent execution is precisely what I want. I want to start a lot of tasks in separate threads, let them do whatever they do, with a big thread pool, and finish when they finish. The point is to generate load for testing load.
Is there anything available in java.util.concurrent that would let me do so? I am reading these javadocs but they are making my head spin now.
You can use the scheduleAtFixedRate(control, 10l, 1l, TimeUnit.SEDONDS) scheduler to create and execute new tasks (in other threads), similar to:
final ScheduledExecutorService pool = new ScheduledThreadPoolExecutor(100);
Runnable control = new Runnable()
{
public void run() {
Runnable task = new Runnable() {
public void run() {
// do work here
}
};
pool.execute(task);
};
};
pool.scheduleAtFixedRate(control, 5l, 1l, TimeUnit.SECONDS);
I'm not very good in multi-threading, this might be a basic question. But i have'nt been able to find an answer.
Scenario:
Lets say I have an event listener which is fired by something. Every time the event is fired, i want to start a new thread which takes about 3 seconds to execute.
Problem:
The problem is that the event can be fired more than once in a second, and I don't want to start multiple threads at once.
Requirement:
How can I schedule a thread lets say at 1000ms after the event. If the event keeps on firing, i want to keep delaying the scheduled time of thread. This way my thread executes after 1000ms of the last time the event was fired.
The event listener, on start up, creates and starts a new private thread. The thread contain a list of tasks to do and executes them one at a time sequentially. Each time the even listener receives a new event, it creates a new task, and adds it to the list of tasks in the private thread.
EDIT: Eugene suggested using a Thread Pool, which might be beneficial in your case if you have a great amount of work to do with each task taking up considerable amount of time. Take a look at thread pools in Java API, like this: http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
I would use a ScheduledExecutorService - schedule the task to happen in one second and if there is a task already scheduled cancel it and schedule a new one to happen in one second
This way your task will execute one second after the last time the event was triggered.
private class Task implements Runnable {
#Override
public void run() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private Future<?> scheduledTaskHandle;
private class Listener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (scheduledTaskHandle != null && !scheduledTaskHandle.isDone()) {
scheduledTaskHandle.cancel(false);
}
scheduledTaskHandle = executorService.schedule(new Task(), 1, TimeUnit.SECONDS);
}
}
The Task is a Runnable that does your long-running operation. the Listener is your listener class.
In the Listener.actionPerformed method we first check whether a task is already scheduled by using the Future, if it is we cancel it. We don't need to worry about race hazards here is if the tasks finishes in between the call to isDone and the call to cancel then nothing will happen.
If the task is running at the point when the Listener fires then that task will complete, as the cancel method is called with false. Another task will be scheduled to run one second after the firing of the listener or once the currently running task has completed (as we are only using a single thread no more than one task can run).
The Listener will then schedule a new execution of the task to happen in one second.
Sometimes the duration of a repeated task is longer than its period (In my case, this can happen for hours at a time). Think of a repeated task that takes 7 minutes to run and is scheduled to run every 10 minutes, but sometimes takes 15 minutes for each run for a few hours in a row.
The Timer and ScheduledThreadPoolExecutor classes both have a scheduleAtFixedRate method that is usually used for this type of functionality. However, both have the characteristic that they 'try to catch up when they fall behind'. In other words, if a Timer falls behind by a few executions, it builds up a queue of work that will be worked on continuously until it catches back up to the number of runs that would have happened if none of the tasks had taken longer than the specified period. I want to avoid this behavior by skipping the current execution if the previous run is not complete.
I have one solution that involves messing around with the afterExecution method of a pooled executor, recalculating a delay, and rescheduling the runnable with the new delay, but was wondering if there's a simpler way, or if this functionality already exists in a common library somewhere. I know about scheduling with a fixed delay rather than a fixed period, but this will not work for me since it's important to try to execute the tasks at their fixed times. Are there any simpler options than my afterExecution solution?
I think what you want is for the long-running task itself to not run in the ScheduledExecutorService itself, but in a background thread. Then the fixed-rate task will always complete quickly, since it is only used for checking whether to start the actual task in the background (or not, if it's still running from last time).
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
final Runnable actualTask = null;
executorService.scheduleAtFixedRate(new Runnable() {
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private Future<?> lastExecution;
#Override
public void run() {
if (lastExecution != null && !lastExecution.isDone()) {
return;
}
lastExecution = executor.submit(actualTask);
}
}, 10, 10, TimeUnit.MINUTES);
You could use scheduleWithFixedDelay method instead. It's similar but this one does not have a queue for missed runs and instead starts counting again only when the current Runnable was terminated.
The documentation states the reexecution of the Runnable will be scheduled based on the delay parameter:
The delay between the termination of one execution and the commencement of the next.
Make a third class, say called Coordinator. Coordinator has a synchronized startRunning() method which sets isRunning to true and returns true if another thread was not running already. There should also be a synchronized stopRunning method which sets isRunning to false. It returns true if a runnable is already running. You make a single instance of this class and pass a reference to all of the runnables you construct. In the runnable's run method you first call startRunning and check the return to verify that another one isn't running already. Make sure to put the code in run() in a try-finally and call stopRunning from within the finally block.