ScheduledThreadPoolExecutor scheduleWithFixedDelay and "urgent" execution - java

I have the following problem that the standard library doesn't solve well, and I'm wondering if anybody has seen another library out there than can do it so I don't need to hack together a custom solution. I have a task that is currently scheduled on a thread pool using scheduleWithFixedDelay(), and I need to modify the code to handle requests for "urgent" execution of the task related to asynchronous events. Thus, if the task is scheduled to occur with a delay of 5 minutes between executions, and an event occurs 2 minutes after the last completed execution, I would like to execute the task immediately and then have it wait for 5 minutes after the completion of the urgent execution before it runs again. Right now the best solution that I can come up with is to have the event handler call cancel() on the ScheduledFuture object returned by scheduleWithFixedDelay() and execute the task immediately, and then set a flag in the task to tell it to reschedule itself with the same delay parameters. Is this functionality available already and I'm just missing something in the documentation?

If you are using ScheduledThreadPoolExecutor there is a method decorateTask (well in fact there are two, for Runnable and Callable tasks) that you can override to store a reference to the task somewhere.
When you need urgent execution, you just call run() on that reference which makes it run and rescheduled with same delay.
A quick hack-up attempt:
public class UrgentScheduledThreadPoolExecutor extends
ScheduledThreadPoolExecutor {
RunnableScheduledFuture scheduledTask;
public UrgentScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize);
}
#Override
protected RunnableScheduledFuture decorateTask(Runnable runnable,
RunnableScheduledFuture task) {
scheduledTask = task;
return super.decorateTask(runnable, task);
}
public void runUrgently() {
this.scheduledTask.run();
}
}
which can be used like this:
public class UrgentExecutionTest {
public static void main(String[] args) throws Exception {
UrgentScheduledThreadPoolExecutor pool = new UrgentScheduledThreadPoolExecutor(5);
pool.scheduleWithFixedDelay(new Runnable() {
SimpleDateFormat format = new SimpleDateFormat("ss");
#Override
public void run() {
System.out.println(format.format(new Date()));
}
}, 0, 2L, TimeUnit.SECONDS);
Thread.sleep(7000);
pool.runUrgently();
pool.awaitTermination(600, TimeUnit.SECONDS);
}
}
and produces the following output:
06
08
10
11
13
15

as requested (soz, in a hurry) my EventBasedExecutor
Warning: This currently only works for tasks that are scheduled in a periodic run. You can change the code to handle all the tasks, I so far haven't because I only have the periodically run task. I also run this in a signle-threaded threadpool (I only need one scheduled runner thread that is that runs in one dedicated thread all the time every X seconds)
Here we go:
public class EventBasedExecutor extends ScheduledThreadPoolExecutor implements EventBasedExecutorService {
private List<RunnableScheduledFuture<?>> workers = new ArrayList<>();
private int index;
public EventBasedExecutor(int corePoolSize) {
super(corePoolSize, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("message-sender-%d").build());
}
#Override
protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
if(!workers.contains(runnable)) {
workers.add(task);
}
return super.decorateTask(runnable, task);
}
#Override
public void executeEarly() {
if(index >= workers.size()) {
index = 0;
}
if(workers.size() == 0) {
return;
}
RunnableScheduledFuture<?> runnableScheduledFuture = workers.get(index);
index ++;
execute(runnableScheduledFuture);
System.out.println("Executing");
}
public static void main(String[] args) throws InterruptedException {
EventBasedExecutor executor = new EventBasedExecutor(10);
long currentTimeMillis = System.currentTimeMillis();
// this will never run
executor.scheduleAtFixedRate(() -> {
System.out.println("hello");
}, 5000, 5000, TimeUnit.HOURS);
executor.executeEarly();
System.out.println("Run after: " + (System.currentTimeMillis() - currentTimeMillis));
}
}
This will execute the task in the dedicated worker thread.
It will print:
Executing
hello
Run after: 39
Have fun hacking :)
artur

There is also an obvious simple solution that does not require a new class.
The idea is to cancel the schedule on notification and re-schedule again:
class MyClass {
final static int DECISION_POINT = 1; //millisecond
final ScheduledExecutorService executor = newSingleThreadScheduledExecutor();
private ScheduledFuture<?> periodicFuture;
MyClass() {
periodicFuture = executor.scheduleWithFixedDelay(this::doWork, 1, 2,
TimeUnit.SECONDS);
}
void doWorkAsap() {
if (periodicFuture.getDelay(TimeUnit.MILLISECONDS) > DECISION_POINT) {
periodicFuture.cancel(true);
periodicFuture = executor.scheduleWithFixedDelay(this::doWork,
0, 2000, TimeUnit.MILLISECONDS);
}
}
void doWork() { ... }
}
This only works well in certain situations where delay between tasks is reasonably big relative to overall system performance and overhead of creating new ScheduledFuture is acceptable. Also, special attention needs to be paid to the point of no return, called DECISION_POINT here, where it makes no more sense to schedule the new future, as natural order of things would be fast enough. For the tighter schedules than in the example above, use an approach similar to the pandaab one.

Related

How to make Java code that opens the program hourly

I'm trying to make code that opens hourly programs made in Java. I have little knowledge of java. I tried to do similar below but it doesn't work as I want.
Code:
public static void main(String[] args) throws Exception {
for(int i = 0; i < 5; i++) {
Runtime runtime = Runtime.getRuntime();
String[] s = new String[] {"C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"};
Process process = runtime.exec(s);
}
}
If you are looking for running this program in a scheduled manner, you can use something like
Task Scheduler in windows or Crontab in case of UNIX systems.
You need not install and run Java for that. But, if you really need it to be executed using a java code, then you can use inbuilt scheduling options in Java. One of the approach is to use a TimerTask . Added an example below
public class Task extends TimerTask {
#Override
public void run() {
try {
// I don't know, what is this app, basically you execute the logic here
Runtime runtime = Runtime.getRuntime();
String[] s = new String[] { "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" };
Process process = runtime.exec(s);
} catch (IOException e) {
// Do your thing with the errors!
e.printStackTrace();
}
}
}
And your scheduler goes like this.
public class Scheduler {
public static void main(String[] args) {
//Create a timer for scheduling
Timer schduleManager = new Timer();
//Create your task instance
Task taskInstance = new Task();
//Scheduler your task repeatedly - every one hour
schduleManager.schedule(taskInstance, 0, TimeUnit.HOURS.toMillis(1));
System.out.println(TimeUnit.HOURS.toMillis(1));
// Keep your code running - an eg.
while(true);
}
}
The program has to be exited forcefully with a Cntrl+C or console kill. There are other similar options , using different libraries as well, like
java.util.concurrent.ScheduledExecutorService
Quartz Scheduler
And more. You can explore on this.
If you are using spring boot then you can use Scheduler annotation
#Scheduled(fixedDelay = 60 * 60 * 1000
This seems to be a job requiring Java's ScheduledExecutorService. According to Java's documentation
The ScheduledExecutorService interface supplements the methods of its
parent ExecutorService with schedule, which executes a Runnable or
Callable task after a specified delay. In addition, the interface
defines scheduleAtFixedRate and scheduleWithFixedDelay, which executes
specified tasks repeatedly, at defined intervals.
Here's an example from its Javadoc that sets up a ScheduledExecutorService to beep every ten seconds for an hour:
import static java.util.concurrent.TimeUnit.*;
class BeeperControl {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void beepForAnHour() {
final Runnable beeper = new Runnable() {
public void run() { System.out.println("beep"); }
};
final ScheduledFuture<?> beeperHandle =
scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
scheduler.schedule(new Runnable() {
public void run() { beeperHandle.cancel(true); }
}, 60 * 60, SECONDS);
}
}
Here is a link to a StackOverflow answer that uses ScheduledExecutorService to run a task at a specific time.
Another alternative is to run your task as a CRON job. Here's a link to a StackOverflow answer that uses CRON to schedule a Java program.
If I understood your question correctly you can use Thread.sleep() to idle and then start the Process.
So I guess something like this would work:
public static void main(String[] args) throws InterruptedException, IOException {
ProcessBuilder pb = new ProcessBuilder("path\\to\\file.exe");
while (true) {
pb.start();
Thread.sleep(Duration.ofHours(1).toMillis());
}
}

How to run tasks at a scheduled rate that DON'T wait for the task before it?

Currently, I have some code that I need to run every (for example) 33 milliseconds. However, the operation that I am calling requires around 270ms. Is there a way to schedule my tasks so that they run regardless of the task before them?
I have tried implementing a ScheduledExecutorService variable and running the task at a "ScheduledFixedRate" but that currently waits for the task before it.
Runnable imageCapture = new Runnable() {
public void run() {
// code that takes approximately 270ms
}
};
executor = Executors.newScheduledThreadPool(4);
executor.scheduleAtFixedRate(imageCapture, 0, 33, TimeUnit.MILLISECONDS);
Split the task in two: one makes actual computations and another is executed periodically and starts the first one:
executor = Executors.newScheduledThreadPool(4);
Runnable imageCapture = new Runnable() {
public void run() {
// code that takes approximately 270ms
}
};
Runnable launcher = new Runnable() {
public void run() {
executor.execute(imageCapture);
}
};
executor.scheduleAtFixedRate(launcher, 0, 33, TimeUnit.MILLISECONDS);

How to test ScheduledExecutorService exception handling in Junit?

I have a task which I scheduled to run every 30 mins. I used ScheduledExecutorService to schedule.
I want to test(junit) the exception handling for ScheduledExecutorService such that when ever there is an exception thrown, the thread is not dying because of the exception.
My code :
public enum MonitorTask {
TIMER;
private final AtomicBoolean isPublishing = new AtomicBoolean(false);
private final long period = 18000000
public synchronized boolean initialize() {
return initialize(period, period);
}
/**
* #return true, if call was successful i.e. Timer task was scheduled
*/
boolean initialize(long delay, long period) {
if (isPublishing.get()) {
log.warn("Already monitoring for new feature data");
return false;
}
//execute on daemon thread
ScheduledExecutorService scheduledExecutorService =
Executors.newSingleThreadScheduledExecutor(runnable -> {
Thread thread = new Thread(runnable);
thread.setDaemon(true);
return thread;
}
);
Runnable runnableTask = () -> {
try {
DataPublisher.INSTANCE.update(DateTime.now());
} catch (Throwable e) {
log.warn("Failed to check for new Data!", e);
}
};
scheduledExecutorService.scheduleAtFixedRate(runnableTask, delay, period, TimeUnit.MILLISECONDS);
isPublishing.set(true);
return true;
}
}
As for now, my unit test check for the functionality:
public class MonitorTaskTest {
#Test
public void testInitialize() throws Exception {
AtomicInteger val = new AtomicInteger(0);
DataProvider provider = testProvider(val);
assertEquals(0, val.get());
// this should update val every 10 ms ( adds 1 to val )
Assert.assertTrue(MonitorTask.TIMER.initialize(0, 10));
assertEquals(0, val.get());
DataPublisher.INSTANCE.registerForNewData(provider, DateTime.now());
// wait for 3 updates
Thread.sleep(10 * 3);
Assert.assertTrue("Expected val to be >= 3 but is " + val.get(), val.get() >= 3);
}
#Before
public void setUp() {
DataPublisher.INSTANCE.clear();
}
private static DataProvider testProvider(final AtomicInteger ai) {
return new DataProvider() {
private AtomicInteger val = ai;
#Override public boolean update(DateTime dateTime) throws Exception {
val.incrementAndGet();
return true;
}
#Override public boolean exists(DateTime dateTime) {
return true;
}
#Override public void close() throws Exception {
}
};
}
}
I think you are going down the wrong rabbit hole here. Meaning: when you check the javadoc for the method you are using, you find:
Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.)
In other words: you are asking how to test something that is guaranteed to work by the Java system library you are using. And in that sense you are wasting your time.
You might rather spend time to improve your code to make it easier to test. You see - when your class would receive an ExecutorService object (instead of creating one for itself) you could pass in a same thread executor for your unit tests. And all of a sudden, your unit tests can run on one thread which makes the whole testing a lot easier - as it allows you to get rid of your sleep statements in your tests. (and those sleep statements are much more of a problem than chances that threads are not re-started although the system library guarantees you to do so).
Beyond that: your runnable is already written in a way that should guarantee that threads running this code never die (of course, it is questionable to catch Throwable). But in order to test that, I guess you only need another "test provider" where update() throws any kind of exception.

How do I schedule a task to run once?

I want to delay doing something, along the lines of setting a countdown timer that will "do a thing" after a certain amount of time.
I want the rest of my program to keep running while I wait, so I tried making my own Thread that contained a one-minute delay:
public class Scratch {
private static boolean outOfTime = false;
public static void main(String[] args) {
Thread countdown = new Thread() {
#Override
public void run() {
try {
// wait a while
System.out.println("Starting one-minute countdown now...");
Thread.sleep(60 * 1000);
// do the thing
outOfTime = true;
System.out.println("Out of time!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
countdown.start();
while (!outOfTime) {
try {
Thread.sleep(1000);
System.out.println("do other stuff here");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
While this worked, more-or-less, it seemed like there should be a better way of doing this.
After some searching, I found a bunch of questions like these but they don't really address what I'm trying to do:
How do I schedule a task to run at periodic intervals?
How i can run my TimerTask everyday 2 PM
How to run certain task every day at a particular time using ScheduledExecutorService?
Java execute task with a number of retries and a timeout
I don't need anything this complicated; I just want to do a single thing after a certain amount of time while letting the rest of the program still run.
How should I go about scheduling a one-time task to "do a thing"?
While the java.util.Timer used to be a good way to schedule future tasks, it is now preferable1 to instead use the classes in the java.util.concurrent package.
There is a ScheduledExecutorService that is designed specifically to run a command after a delay (or to execute them periodically, but that's not relevant to this question).
It has a schedule(Runnable, long, TimeUnit) method that
Creates and executes a one-shot action that becomes enabled after the given delay.
Using a ScheduledExecutorService you could re-write your program like this:
import java.util.concurrent.*;
public class Scratch {
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static void main(String[] args) {
System.out.println("Starting one-minute countdown now...");
ScheduledFuture<?> countdown = scheduler.schedule(new Runnable() {
#Override
public void run() {
// do the thing
System.out.println("Out of time!");
}}, 1, TimeUnit.MINUTES);
while (!countdown.isDone()) {
try {
Thread.sleep(1000);
System.out.println("do other stuff here");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
scheduler.shutdown();
}
}
One of the nice things you get by doing things this way is the ScheduledFuture<?> object you get back from calling schedule().
This allows you to get rid of the extra boolean variable, and just check directly whether the job has run.
You can also cancel the scheduled task if you don't want to wait anymore by calling its cancel() method.
1See Java Timer vs ExecutorService? for reasons to avoid using a Timer in favor of an ExecutorService.
Thanks it worked for me. I used scheduler to schedule a task at a batchinterval calculated at runtime.
manualTriggerBatchJob.setSchedulingProperties(pblId, batchInterval);
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(5);
#SuppressWarnings("unchecked")
ScheduledFuture scheduledFuture =
scheduledExecutorService.schedule(manualTriggerBatchJob,
batchIntervalInMin,TimeUnit.MILLISECONDS);

Waiting list of threads in java

I'm writing a swing application with HttpClient and I need a way to make a download list because I need to wait 1 minute (for example) before starting a new download.
So I would like to create a waiting list of threads (downloads).
I would have a class that takes a time parameter and contains a list of threads and when I add a thread in the list it starts if there is no running thread. Otherwise it waits for its turn.
Is there any tool to do that ?
Thanks a lot for your help.
Yes. ScheduledExecutorService. You can create a fixed length service via Executors.newScheduledThreadPool(corePoolSize). When you are ready to submit the task to wait the amount of time just submit it to ScheduledExecutorService.schedule
ScheduledExecutorService e = Executors.newScheduledThreadPool(10)
private final long defaultWaitTimeInMinutes = 1;
public void submitTaskToWait(Runnable r){
e.schedule(r, defaultWaitTimeInMinutes, TimeUnit.MINUTES);
}
Here the task will launch in 1 minute from the time of being submitted. And to address your last point. If there are currently tasks being downloaded (this configuration means 10 tasks being downloaded) after the 1 minute is up the runnable submitted will have to wait until one of the other downloads are complete.
Keep in mind this deviates a bit from the way you are designing it. For each new task you wouldnt create a new thread, rather you would submit to a service that already has thread(s) waiting. For instance, if you only want one task to download at a time you change from Executors.newScheduledThreadPool(10) to Executors.newScheduledThreadPool(1)
Edit: I'll leave my previous answer but update it with a solution to submit a task to start exactly 1 minute after the previous task completes. You would use two ExecutorServices. One to submit to the scheuled Executor and the other to do the timed executions. Finally the first Executor will wait on the completion and continue with the other tasks queued up.
ExecutorService e = Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1)
public void submitTask(final Runnable r){
e.submit(new Runnable(){
public void run(){
ScheduledFuture<?> future= scheduledService.schedule(r, defaultWaitTimeInMinutes, TimeUnit.MINUTES);
future.get();
}
});
}
Now when the future.get(); completes the next Runnable submitted through submitTask will be run and then scheduled for a minute. Finally this will work only if you require the task to wait the 1 minute even if there is no other tasks submitted.
I think this would be a wrong way of going about the problem. A bit more logical way would be to create "download job" objects which will be added to a job queue. Create a TimerTask which would query this "queue" every 1 minute, pick up the Runnable/Callable jobs and submit them to the ExecutorService.
You could use the built-in ExecutorService. You can queue up tasks as Runnables and they will run on the available threads. If you want only a single task to run at a time use newFixedThreadPool(1);
ExecutorService executor = Executors.newFixedThreadPool(1);
You could then append an artificial Thread.sleep at the beginning of each Runnable run method to ensure that it waits the necessary amount of time before starting (not the most elegant choice, I know).
The Java Concurrency package contains classes for doing what you ask. The general construct you're talking about is an Executor which is backed by a ThreadPool. You generate a list of Runables and send them to an Executor. The Executor has a ThreadPool behind it which will run the Runnables as the threads become available.
So as an example here, you could have a Runnable like:
private static class Downloader implements Runnable {
private String file;
public Downloader(String file) {
this.file = file;
}
#Override
public void run() {
// Use HttpClient to download file.
}
}
Then You can use it by creating Downloader objects and submitting it to an ExecutorService:
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (String file : args) {
executorService.submit(new Downloader(file));
}
executorService.awaitTermination(100, TimeUnit.SECONDS);
}
It is maybe not the best solution but here is what I came up with thanks to the answer of John Vint. I hope it will help someone else.
package tests;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class RunnableQueue
{
private long waitTime;
private TimeUnit unit;
ExecutorService e;
public RunnableQueue(long waitTime, TimeUnit unit) {
e = Executors.newSingleThreadExecutor();
this.waitTime = waitTime;
this.unit = unit;
}
public void submitTask(final Runnable r){
e.submit(new Runnable(){
public void run(){
Thread t = new Thread(r);
t.start();
try {
t.join();
Thread.sleep(unit.toMillis(waitTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
public static void main(String[] args) {
RunnableQueue runQueue = new RunnableQueue(3, TimeUnit.SECONDS);
for(int i=1; i<11; i++)
{
runQueue.submitTask(new DownloadTask(i));
System.out.println("Submitted task " + i);
}
}
}

Categories