A Combination of TimerTask and Timer
In this article, I will give you a brief introduction about what Timer and TimerTask are and then a simple example to help you understand how to use them.
Brief Introduction
1. java.util.TimerTask:
java.util.TimerTask
is a class object which implements Runnable
interface. By implementing the run method in TimerTask, we can tell the program what to do during runnint the task. So, java.util.TimerTask
can be seen as a task object which contains what kinds of works to do when running the thread.
2. java.util.Timer:
java.util.Timer
, on the other hand, is a class object used to schedule tasks for future execution. It is thread-safe, which means that multiple threads can share one Timer object without doing synchronization from other programs. So, java.util.Timer
can be seen as a schedular object to arrange tasks to run.
How to use them
1. Implementation of a TimerTask:
As java.util.TimerTask
implements java.lang.Runnable
, I need to overwrite the run method to declare what I need the thread to do.
import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.TimerTask; /** * @author Hank Lee * Shared from InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class PrintTask extends TimerTask { @Override public void run() { // Gets the system default time-zone. ZoneId zone = ZoneId.systemDefault(); // Returns the scheduled execution time of the most recent actual execution of this task. Long scheduledExecutionTime = this.scheduledExecutionTime(); // Obtains an instance of LocalDateTime from an Instant and zone ID. LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(scheduledExecutionTime), zone); System.out.println("Print message at: "+ dateTime);} }
In the example of PrintTask class, I use run method to print the scheduled execution time obtained by calling the scheduledExecutionTime()
in java.util.TimerTask
. So far, I have already setup a timer task and are waiting for using java.util.Timer
to schedule it.
2. Implementation of a Timer:
To setup a schedular using java.util.Timer
, there is a simple example below:
import java.util.Timer; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class TimerAndTimerTask { public static void main(String[] args) { // create a new timer and give it a name Timer timer = new Timer("PrintTaskTimer"); // schedule the PrintTask class and setup two parameters: delay and period long delay = 0; long period = 2000; timer.schedule(new PrintTask(), delay, period); System.out.println("Timer has already started."); // record the current time Long startTime = System.currentTimeMillis(); // use while loop to restrict the execution while (true) { Long endTime = System.currentTimeMillis(); // when the running time comes to 20 seconds, cancel the timer and break the loop. if ((endTime-startTime)/(1000*20) == 1) { timer.cancel(); System.out.println("Cancel timer. End the program."); break; } } } }
In the example code, I create a new java.util.Timer
object and give it a specified name PrintTaskTimer. Also, I declare two variables of times for deloy and period. Then, use the method schedule(TimerTask task, long delay, long period)
to setup which TimerTask to execute and the times of delay and the period of execution. At that time, the PrintTask is scheduled and will execute every 2 seconds with no delay. In the while loop, I use it to setup that the timer will only run for 20 seconds. When time’s up, the timer will be canceled and end the program. The result of running TimerAndTimerTask
is shown as below:
Timer has already started. Print message at: 2020-05-03T17:01:16.780 Print message at: 2020-05-03T17:01:18.783 Print message at: 2020-05-03T17:01:20.786 Print message at: 2020-05-03T17:01:22.791 Print message at: 2020-05-03T17:01:24.791 Print message at: 2020-05-03T17:01:26.794 Print message at: 2020-05-03T17:01:28.797 Print message at: 2020-05-03T17:01:30.802 Print message at: 2020-05-03T17:01:32.807 Print message at: 2020-05-03T17:01:34.811 Cancel timer. End the program.
As you can see, the differences of execution times between each messages are not exacly 2 seconds. The reason is that it needs some time to execute PrintTask
. No sooner does the execution end than Timer
starts to count for 2 seconds and execute PrintTask
again. If you want to fix the issue, you can use another schedule method called scheduleAtFixedRate(TimerTask task, long delay, long period)
. The example and result are shown as below.
// Just need to change the method here. timer.scheduleAtFixedRate(new PrintTask(), delay, period);
Result:
Timer has already started. Print message at: 2020-05-03T17:18:26.730 Print message at: 2020-05-03T17:18:28.730 Print message at: 2020-05-03T17:18:30.730 Print message at: 2020-05-03T17:18:32.730 Print message at: 2020-05-03T17:18:34.730 Print message at: 2020-05-03T17:18:36.730 Print message at: 2020-05-03T17:18:38.730 Print message at: 2020-05-03T17:18:40.730 Print message at: 2020-05-03T17:18:42.730 Print message at: 2020-05-03T17:18:44.730 Cancel timer. End the program.
Extra Example-1 (Use with java.net.Socket)
Recently, I use java.util.Timer and java.util.TimerTask in my java.net.Socket programs to send messages from server to client to check whether the client is still alive or not. The logic in my implementation is that before the server is waiting for the response from client, I start the schedule to send message periodically. Once the server receive the message from client, I cancel the schedular. With the same logic in client site, I start the schedule to catch the message sent from server and print the message in the console before getting the input from console entered by user. Once the user enters a message, I cancel the schedular. The examples are as below:
The sample code of ServerTask.java
:
import java.io.PrintWriter; import java.util.TimerTask; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class ServerTask extends TimerTask { private PrintWriter outputToClient; public ServerTask (PrintWriter outputToClient) { this.outputToClient = outputToClient; } @Override public void run() { try { // Send the message to Client. outputToClient.println("Are you still there?"); } catch (Exception e) {} } }
In the ServerTask.java
, I use the thread to send message to client.
The sample code of Server.java
:
import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.NoSuchElementException; import java.util.Scanner; import java.util.Timer; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class Server { private final int PORT = 61023; private Socket connection; private Scanner inputFromClient;private PrintWriter outputToClient; public Server() { ServerSocket server = null; try{ // create a new socket server = new ServerSocket(PORT); System.out.println("Starts the server"); while (true){ System.out.println("Waiting for new connections...");// accept connections from client connection = server.accept(); System.out.println("Connection accepted"); // get the OutputStream and InputStream from connection outputToClient = new PrintWriter(connection.getOutputStream(),true); inputFromClient = new Scanner(connection.getInputStream()); try { while (true) { // send messages to client. outputToClient.println("Send messages to server. Or if you want to end the connection, please enter \"q\":"); // create new Timer to schedule TimerTask and start its schedule. Timer timer = new Timer("ServerTaskTimer"); // use delay to let the timer start after 3 seconds. long delay = 3000; long period = 3000; timer.scheduleAtFixedRate(new ServerTask(outputToClient), delay, period); // take input from client String clientMessage = inputFromClient.nextLine(); // Once it receive the message from client, cancel the timer. timer.cancel(); System.out.println("Client says: " + clientMessage); // check if the client wants to end the connection. if ("q".equals(clientMessage)) { System.out.println("Client ends the connection."); break; } }}catch (NoSuchElementException ne) { System.out.println("Client quits the game.");}}} catch (IOException e) { e.printStackTrace();} finally {try { server.close();} catch (IOException e) { }} } public static void main(String[] args) { new Server(); } }
In the Server.java
, it will send a introduction to client first, then start the timer before waiting for response from client. Once getting response, it stops the timer and print the message from client in console until the message is equals to “q”.
The sample code of ClientTask.java
:
import java.util.Scanner; import java.util.TimerTask; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class ClientTask extends TimerTask { private Scanner inputFromServer; public ClientTask(Scanner inputFromServer) { this.inputFromServer = inputFromServer; } @Override public void run() { try { // Print the message from server. System.out.println("ClientTask: " + inputFromServer.nextLine()); } catch (Exception e) {} } }
In the ClientTask.java
, I use the thread to catch message sent from server and print the message to console.
The sample code of Client.java
:
import java.io.*; import java.net.Socket; import java.util.NoSuchElementException; import java.util.Scanner; import java.util.Timer; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class Client { private final static String ADDRESS = "localhost"; private final static int PORT = 61023; private Socket connection; private PrintWriter outputToServer; private Scanner inputFromServer; public Client() { try { // create a socket with the address and port connection = new Socket(ADDRESS, PORT); // get the OutputStream and InputStream from the connection outputToServer = new PrintWriter(connection.getOutputStream(), true); inputFromServer = new Scanner(connection.getInputStream()); Scanner inputFromConsole; // use while loop to listen feedbacks from server. while (true) { try { // read the message from server String serverMessage = inputFromServer.nextLine(); // print the message from server. System.out.println(serverMessage); // create a Timer to schedule ClientTask which use to receive the message from // ServerTask. Timer timer = new Timer("ClientTaskTimer"); // use delay to let the timer start after 3 seconds. long delay = 3000; long period = 3000; timer.scheduleAtFixedRate(new ClientTask(new Scanner(connection.getInputStream())), delay, period); // get input from console and use PrintWriter to send the input to server. inputFromConsole = new Scanner(System.in); String messageToServer = inputFromConsole.nextLine(); outputToServer.println(messageToServer); // After sending message to server, cancel the timer. timer.cancel(); // check if client wants to end the connection if ("q".equals(messageToServer)) { System.out.println("End the connection."); inputFromConsole.close(); break; } // If the server is shut down, end the while loop. } catch (NoSuchElementException nsee) { nsee.printStackTrace(); System.out.println("The server is out of service."); break; } } System.exit(0); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new Client(); } }
In the Client.java
, it prints the introduction from server first, and setup the timer then waiting for the input from console. Once receiving the input, it stops the timer and send the message to server until the input is equals to “q”.
In Server.java
and Client.java
, I setup a delay time for 3 seconds, as I want timers to start tasks after 3 seconds.
The console output in server site will be:
Starts the server Waiting for new connections... Connection accepted Client says: Hi Server Client says: Hello Client says: q Client ends the connection. Waiting for new connections...
Server.java
will execute until stoping it manually.
The console output in client site will be:
Send messages to server. Or if you want to end the connection, please enter "q": ClientTask: Are you still there? Hi Server Send messages to server. Or if you want to end the connection, please enter "q": ClientTask: Are you still there? Hello Send messages to server. Or if you want to end the connection, please enter "q": ClientTask: Are you still there? ClientTask: Are you still there? ClientTask: Are you still there? q End the connection.
The messages which starts from ClientTask: are printed in ClientTask.java
.
Extra Example-2 (Use with java.net.Socket and multi-thread of clients)
It’s time to handle multi-thread in the server site with Timer and TimerTask. It’s very easy to implement it by just moving part of the codes of Server.java
to another class object which extends java.lang.Thread
, which is ClientThreadHandler.java
in my sample code. There is no need to change the code in Client.java
and ClientTask.java
. The codes are shown as below.
The sample code of Server.java
with handling multi-thread:
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class Server { private final int PORT = 61023; private Socket connection; public Server() { ServerSocket server = null; List<ClientThreadHandler> clients = new ArrayList<>(); try{ // create a new socket server = new ServerSocket(PORT); System.out.println("Starts the server"); while (true){ System.out.println("Waiting for new connections...");// accept connections from client connection = server.accept(); clients.add(new ClientThreadHandler(connection)); System.out.println("Connection accepted"); System.out.println("Start the thread."); clients.get(clients.size()-1).start(); }} catch (IOException e) { e.printStackTrace();} finally {try { server.close();} catch (IOException e) { }} } public static void main(String[] args) { new Server(); } }
As you can see, in the Server.java
, I just accept connections, and use the connection to create an instance of ClientThreadHandler.java
and put the instance into a list, then start the instance.
The sample code of ClientThreadHandler.java
which extends java.lang.Thread
:
import java.io.IOException; import java.io.PrintWriter; import java.net.Socket; import java.util.NoSuchElementException; import java.util.Scanner; import java.util.Timer; /** * @author Hank Lee * Shared in InformisTry -- https://jumperc2p.github.io/InformisTry/ * */ public class ClientThreadHandler extends Thread { private Scanner inputFromClient;private PrintWriter outputToClient; public ClientThreadHandler(Socket connection) { // get the OutputStream and InputStream from connection try { outputToClient = new PrintWriter(connection.getOutputStream(),true); inputFromClient = new Scanner(connection.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { while (true) { // send messages to client. outputToClient.println("Send messages to server. Or if you want to end the connection, please enter \"q\":"); // create new Timer to schedule TimerTask and start its schedule. Timer timer = new Timer("ServerTaskTimer"); // use delay to let the timer start after 3 seconds. long delay = 3000; long period = 3000; timer.scheduleAtFixedRate(new ServerTask(outputToClient), delay, period); // take input from client String clientMessage = inputFromClient.nextLine(); // Once it receive the message from client, cancel the timer. timer.cancel(); System.out.println("Client says: " + clientMessage); // check if the client wants to end the connection. if ("q".equals(clientMessage)) { System.out.println("Client ends the connection."); break; } }}catch (NoSuchElementException ne) { System.out.println("Client quits the game.");} } }
In the ClientThreadHandler.java
, I just paste codes used to react with client from Server.java
.
That’s all. No thing is difficult.
Sample Code
The sample code can be downloaded here:
- Extra example -1 is in the package of timer_example.
- Extra example -2 is in the package of multithread_socket_with_timer.
If you would like to use the code provided here, please indicate the source.
Using java.util.Timer
and java.util.TimerTask
can help us execute other programs at the same time. But I still need more practices to understand the knowledge of Thread.
If you have any options about the article, please feel free to give me a comment below. Thank you.
This article is also posted at : https://jumperc2p.github.io/InformisTry/posts/a_combination_of_timertask_and_timer/