The ExecutorService Interface is not the end of Executors. The package provides another specialized interface ScheduledExecutorService which is capable of executing tasks after a certain delay, or repeating tasks at fixed intervals.
I decided to test the interface.
The problem was simple - create a Jobber that starts after a certain time has elapsed
and have a Job Monitor that monitors the performance of the Jobber.
The first step was to create a jobber:
The next step was to create a monitor:
The Executor used in the code is a instance of ScheduledThreadPoolExecutor. To schedule the Jobber instance to start after 10 seconds we have used the schedule API:
Also I have used the main thread to audit the status of the Executor threads at intervals of 30 seconds. On running the code:
There is also a scheduleAtFixedRate method available which attempts to start the iterations after fixed intervals. The scheduleWithFixedDelay method ensures that a certain amount of time elapses between the completion of one iteration and the beginning of the next run for the given Runnable instance.
I decided to test the interface.
The problem was simple - create a Jobber that starts after a certain time has elapsed
and have a Job Monitor that monitors the performance of the Jobber.
The first step was to create a jobber:
classJobberimplements Callable<Void> {The Jobber here is a Callable that processes the jobs supplied in a jobs array. After processing of each job it sleeps for a period of five seconds and then starts the next job. (A Five second sleep does not mean that the job will start on the 6th second. It will start when the thread is given processor time after it has slept for 5 seconds.)
@Override
publicVoid call() {
String threadName = "[" + Thread.currentThread().getName() + "]";
System.out.println(threadName + " : Starting the Jobs...");
for (int i = 0; i < ScheduledExecutor.MAX_JOBS; i++) {
int result = 0;
int val = 0;
synchronized (ScheduledExecutor.jobs) {
val = ScheduledExecutor.jobs[i];
}
for (long j = 0; j < val; j++) {
result = result + 1;
}
synchronized (ScheduledExecutor.results) {
ScheduledExecutor.results[i] = result;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
thrownew RuntimeException(e);
}
}
System.out.println(threadName + " : Completed the Jobs.");
returnnull;
}
}
The next step was to create a monitor:
classResultMonitorimplements Runnable {This class is much more simpler. ResultMonitor is a Runnable that simply checks the result array to see the number of jobs that have reached completion and reports back accordingly. Now the main class:
@Override
publicvoid run() {
String threadName = "[" + Thread.currentThread().getName() + "]";
int count = 0;
synchronized (ScheduledExecutor.results) {
for (Integer result : ScheduledExecutor.results) {
if (null != result) {
count++;
}
}
}
System.out.println(threadName + " : Total results found " + count);
}
}
publicclass ScheduledExecutor {As seen here the ScheduledExecutor class creates a static array of jobs and has an empty result array. The two arrays are referenced by the Jobber and ResultMonitor classes.
publicstaticfinalint MAX_JOBS = 6;
publicstaticfinalint[] jobs;
publicstaticfinal Integer[] results = new Integer[MAX_JOBS];
static {
jobs = newint[MAX_JOBS];
Random random = new Random((long) Math.random() * 3);
for (int i = 0; i < jobs.length; i++) {
int nxtNo = random.nextInt();
nxtNo = nxtNo < 0 ? nxtNo * -1 : nxtNo;
jobs[i] = nxtNo / 1000;
}
}
publicstaticvoid main(String[] args) throws InterruptedException {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
ScheduledFuture<?> jobberFeature = scheduledExecutorService.schedule(
new Jobber(), 10, TimeUnit.SECONDS);
ScheduledFuture<?> monitorFeature = scheduledExecutorService
.scheduleWithFixedDelay(new ResultMonitor(), 0, 10,
TimeUnit.SECONDS);
while (true) {
System.out.println("[" + Thread.currentThread().getName()
+ "] Testing thread Status: "
+ "\n Is Jobber Done ? " + jobberFeature.isDone()
+ "\n Is Monitor Done ? " + monitorFeature.isDone());
if (jobberFeature.isDone()) {
System.out.println("Terminating the Monitor as jobber is complete");
monitorFeature.cancel(true);
break;
}
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException exception) {
scheduledExecutorService.shutdownNow();
System.exit(0);
}
}
scheduledExecutorService.shutdown();
}
}
The Executor used in the code is a instance of ScheduledThreadPoolExecutor. To schedule the Jobber instance to start after 10 seconds we have used the schedule API:
public<V> ScheduledFuture<V> schedule(Callable<V> callable,The return type is a ScheduledFuture instance:
long delay, TimeUnit unit)
publicinterfaceScheduledFuture<V> extends Delayed, Future<V> {Similarly to have a repeating task the API used is :
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,Within the main thread I check if the Jobber task is done. (Using the isDone() method). If the jobber is complete, then the MonitorFeature is cancelled. Without the cancellation the task will keep repeating endlessly.
long delay, TimeUnit unit)
Also I have used the main thread to audit the status of the Executor threads at intervals of 30 seconds. On running the code:
[pool-1-thread-1] : Total results found 0As seen the Jobber thread started after a certain time had elapsed since program start. Also the Executor used different threads for executing the ResultMonitor task.
[main] Testing thread Status:
Is Jobber Done ? false
Is Monitor Done ? false
[pool-1-thread-2] : Starting the Jobs...
[pool-1-thread-1] : Total results found 0
[pool-1-thread-2] : Completed the Jobs.
[pool-1-thread-2] : Total results found 6
[main] Testing thread Status:
Is Jobber Done ? true
Is Monitor Done ? false
Terminating the Monitor as jobber is complete
There is also a scheduleAtFixedRate method available which attempts to start the iterations after fixed intervals. The scheduleWithFixedDelay method ensures that a certain amount of time elapses between the completion of one iteration and the beginning of the next run for the given Runnable instance.