How it works...

In this recipe, you implemented the MyScheduledTask class to implement a custom task that can be executed on a ScheduledThreadPoolExecutor executor. This class extends the FutureTask class and implements the RunnableScheduledFuture interface. It implements the RunnableScheduledFuture interface because all the tasks executed in a scheduled executor must implement this interface and extend the FutureTask class. This is because this class provides valid implementations of the methods declared in the RunnableScheduledFuture interface. All the interfaces and classes mentioned earlier are parameterized classes and they possess the type of data that will be returned by the tasks.

To use a MyScheduledTask task in a scheduled executor, you override the decorateTask() method in the MyScheduledThreadPoolExecutor class. This class extends the ScheduledThreadPoolExecutor executor, and the method provides a mechanism to convert the default scheduled tasks implemented by the ScheduledThreadPoolExecutor executor into MyScheduledTask tasks. So, when you implement your own version of scheduled tasks, you have to implement your own version of a scheduled executor.

The decorateTask() method simply creates a new MyScheduledTask object with four parameters. The first one is a Runnable object that is going to be executed in the task. The second one is the object that is going to be returned by the task. In this case, the task won't return a result, so you used the null value. The third one is the task that the new object is going to replace in the pool and the latest is the executor that will execute the task. In this case, you use the this keyword to reference the executor that is creating the task.

The MyScheduledTask class can execute delayed and periodic tasks. You implemented two methods with all of the necessary logic to execute both kinds of tasks. They are the getDelay() and run() methods.

The getDelay() method is called by the scheduled executor to know whether it has to execute a task. The behavior of this method changes in delayed and periodic tasks. As mentioned earlier, the constructor of the MyScheduledClass class receives the original ScheduledRunnableFuture object that was going to execute the Runnable object and stores it as an attribute of the class to have access to its methods and data. When we execute a delayed task, the getDelay() method returns the delay of the original task; however, in the case of a periodic task, the getDelay() method returns the difference between the startDate attribute and the actual date.

The run() method is the one that executes the task. One particularity of periodic tasks is that you have to put the next execution of the task in the queue of the executor as a new task if you want the task to be executed again. So, if you're executing a periodic task, you establish the startDate attribute value and add it to the actual date and period of the execution of the task and store the task again in the queue of the executor. The startDate attribute stores the date when the next execution of the task will begin. Then, you execute the task using the runAndReset() method provided by the FutureTask class. In the case of delayed tasks, you don't have to put them in the queue of the executor because they can only be executed once.

You also have to take into account whether the executor has been shut down. If yes, you don't have to store the periodic tasks in the queue of the executor again.

Finally, you overrode the scheduleAtFixedRate() method in the MyScheduledThreadPoolExecutor class. We mentioned earlier that for periodic tasks, you establish the value of the startDate attribute using the period of the task, but you haven't initialized that period yet. You have to override this method that receives this period as a parameter; do this to pass it to the MyScheduledTask class so it can use it.

The example is complete with the Task class that implements the Runnable interface, and it is the task executed in the scheduled executor. The main class of the example creates a MyScheduledThreadPoolExecutor executor and sends the following two tasks to them:

  • A delayed task, which is to be executed 1 second after the actual date
  • A periodic task, which is to be executed for the first time a second after the actual date and then every 3 seconds

The following screenshot shows part of the execution of this example. You can check whether the two kinds of tasks are executed properly:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.79.206