Single thread with a delay to start - java

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.

Related

Which one of these two methods should I use to stop correctly a scheduled thread?

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.

Skip to next task in a single threaded ExecutorSerivce?

I am considering an implementation of an ExecutorService to run a series of tasks. I plan to use the internal queue to have a few tasks waiting for their turn to run. Is there some way to interrupt the task (the Runnable) that is currently running in an ExecutorService thread, and keep the thread alive to run the next task? Or is only possible to call .shutdown() and then create a new ExecutorService?
I have found this and wanted to know if there are any other solutions.
Instead of interfering with the threads you may want to have a Task class (that extends or wraps the Runnable) which implements an interrupt mechanism (e.g. a boolean flag).
When you execute your task you need to check this flag periodically and if it is set, the task should stop what it is doing. You might want to return a specific result at this point, that tells your code that the task was cancelled succesfully.
If a user now decides that he no longer requires the results from this task,
you will have to set this flag. However the task might have already completed at this point of time so you still need to deal with the cases where the result already exists but the user does no longer care about it.
An interrupt on a thread level does not guarantee that the thread stops working. This will only work if the thread is in a state where it can receive an interrupt.
Also you should not interfere with the Threads of the ExecutorSerivce directly, as you might unintentionally stop a different task or stop the ExecutorSerivce from working properly.
Why would you want to kill that task and continue with the next one? If it is a question of times you can define that the threads that are taking longer than you declared in the method that executes them are automatically canceled. E.g:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 60, TimeUnit.SECONDS); // Timeout of 60 seconds.
executor.shutdown();
If any of the threads takes longer than 60 seconds it will throw a cancellation.Exception() that you must catch

How to start, pause, continue a task that executes every 5 seconds as a "keep busy" task

I need to have some routine R which I can start and it executes a task T every 5 seconds.
Then I need to pause this repeating routine R - but ensuring that once it started a task T, this task finishes and only then the repeating routine stops starting the next task. Each started task should be allowed to finish!
The task itself takes maximum 2 seconds, so there is no overlap in the repetition!
Also I need to ensure that another routine R2 starts only after the task T has finished.
So basically this is how it should look like:
start R
- R starts T the first time
- T runs and finishes, this task T takes maximum 2 seconds
- T starts again after 5 seconds it started the first time
now stop R (because user pressed a button)
- let T finish
- stop R from starting a new Task
continue with R2 (basically the task from which the button has been pressed)
BUT continue with R2 ONLY AFTER T has finished for sure! - and R will not repeat any new T
once R2 is done continue with R
- so R will start a new task T
So basically I need the routine R with task T as some kind of a "keep busy routine" while the user reads text for example.
When the user is done reading and wants to continue by pressing on a button, the "keep busy routine" should stop and continue only again after the user's intended task has finished that was triggered by the button press in the first place
So I found
private final static ScheduledExecutorService scheduler = Executors
.newScheduledThreadPool(1);
// Schedule a task to run every 5 seconds with no initial delay.
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
..do task T
}
}, 0L, 5L, TimeUnit.SECONDS);
But all the stopping, continuing and the waiting for T to finish before R2 continues I do not know how to do propperly.
I suggest you make the problem much simpler.
Have a recurring task which starts ever 5 seconds.
the first thing does is check a volatile flag and if set, returns without doing anything.
To turn this process, unset the flag. To pause it, set the flag.
You task can do more than one thing. If it needs to do an R2 after T finishes, you can check for this and execute it in the same task. There is no need to create another task as such.
Note: if you add R2 to the same ExecutorService as T, it has to wait for it to finish before it can start R2. This single threaded service can only do one thing at a time.
The ScheduledExecutorService can be stopped with the shutdown and awaitTermination methods.
Information about the methods to use with ScheduledExecutorService can be found here:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html
And more information about the shutdown and await termination methods can be found here:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html
Shutdown seems to stop the executor from adding, accepting new tasks. The awaitTermination method lets you wait for the ending of the execution of the last task.
This should let you stop the executor and add different tasks to it.
(Avoid the the shutdownNow method.)

How to remove a task from ScheduledExecutorService?

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().

Schedule a single-threaded repeating runnable in java, but skip the current run if previous run is not finished

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.

Categories