Monday, June 20, 2011

ScheduledThreadPool Example

This article will discuss about Thread pool that can schedule threads to run after a specified interval of time. From Java 5.0+ one can get such pool from Executors using following method –

public static ScheduledExecutorService 
newScheduledThreadPool(int corePoolSize)

Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically. The return type of this method (return type of thread pool) is ScheduledExecutorService. Some of the salient features of ScheduledExecutorService are –


  1. Schedule a Callable or Runnable to run once with a fixed delay after submission
  2. Schedule a Runnable to run periodically at a fixed rate
  3. Schedule a Runnable to run periodically with a fixed delay between executions
  4. Submission returns a ScheduledFutureTask handle which can be used to cancel the task
  5. Like Timer, but supports pooling

Example

Lets look at the example. Suppose we have a thread (i.e.Runnable object) of type MyThread which replicates a typical application behaviour by sleeping for a user defined time duration. The end user configures the MyThread sleep duration by passing the interval as a constructor argument.

public class MyThread implements Runnable {

private int delayTime = 0;

public MyThread(int delayTime) {
this.delayTime = delayTime;
}

public MyThread() {

}

@Override
public void run() {
Thread curThread = Thread.currentThread();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss");
System.out.println(df.format(new java.util.Date()) + " Starting thread " + curThread.getName());
try {
Thread.sleep(delayTime * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println(this.toString());
System.out.println(df.format(new java.util.Date()) + " Ending thread " + curThread.getName());

}

@Override
public String toString() {
return ConcurrencyUtils.getThreadInfo();
}

}
ConcurrencyUtils.java
I have used concurrency utils to print thread id, name and pool information. From the output it is clear that all reuse the same thread. Now this is using ConcurrencyUtils to get Thread info:

public class ConcurrencyUtils {

public static String getThreadInfo() {
StringBuilder sb = new StringBuilder();
Thread curThread = Thread.currentThread();
sb.append("Thread Id: ");
sb.append(curThread.getId());
sb.append("\n");
sb.append("Name: ");
sb.append(curThread.getName());
sb.append("\n");
sb.append("Group: ");
sb.append(curThread.getThreadGroup().getName());
sb.append("\n");
return sb.toString();
}

public static String getShortThreadInfo() {
StringBuilder sb = new StringBuilder();
Thread curThread = Thread.currentThread();
sb.append("Thread Id: ");
sb.append(curThread.getId());
sb.append(", ");
sb.append("Name: ");
sb.append(curThread.getName());
sb.append(", ");
sb.append("Group: ");
sb.append(curThread.getThreadGroup().getName());
sb.append("\n");
return sb.toString();
}

public static String retrieveCurrentDate(){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss");
return df.format(new java.util.Date());
}

}
Similarly we have other thread which does the calculation of 2 numbers:

public class Calculator implements Callable<Integer> {

public static final int OPERATION_ADD = 1;

private int param1 = 0;
private int param2 = 0;
private int operation = 0;

public Calculator(int param1, int param2, int operation) {
this.param1 = param1;
this.param2 = param2;
this.operation = operation;
}

public int getParam1() {
return param1;
}

public void setParam1(int param1) {
this.param1 = param1;
}

public int getParam2() {
return param2;
}

public void setParam2(int param2) {
this.param2 = param2;
}

public int getOperation() {
return operation;
}

public void setOperation(int operation) {
this.operation = operation;
}

@Override
public Integer call() throws Exception {
int retValue = 0;
switch (this.operation) {
case 1:
retValue = this.param1 + this.param2;
break;
// Additional cases can be similarly added for
//other mathematical operations

default:
retValue = 0;
break;
}
return Integer.valueOf(retValue) ;
}
}
Demo.java
Finally we have main method, where we will call executor service to do our task. One more thing to note is the invocation of shutdown method on ExecutorService ,which is important else the Java process will not terminate.
public class ScheduledThreadPoolTest {

public static void main(String[] args) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss");
ScheduledExecutorService svc = Executors.newScheduledThreadPool(2);
System.out.println(df.format(new java.util.Date()) + " Time Runnable");
svc.schedule(new MyThread(), 2, TimeUnit.SECONDS);
System.out.println(df.format(new java.util.Date()) + " Time Callable");
ScheduledFuture<Integer> sf = svc.schedule(new Calculator(1, 3,
Calculator.OPERATION_ADD), 5, TimeUnit.SECONDS);
try {
System.out.println("Waiting for value.");
Integer val = sf.get();
System.out.println(df.format(new java.util.Date()) + " Time Callable Retrieve");
System.out.println("Computed Value: " + val);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}

svc.shutdown();

}
}

Download the source


You can download the source from here.


No comments:

Post a Comment

Chitika