HankLee
HankLee

Meds ➡︎ IT, Software Developer, Full Stack Developer, Mentor, Dog Lover

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/

References

  1. Java API - Timer
  2. Java API - TimerTask
  3. Java Timer-Baeldung
CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…

发布评论