Saturday, February 11, 2012

Threads and Executors

There are multiple ways to spawn threads in Java.

The most basic way is to implement the Runnable interface. Any class implementing this interface can be spawned off and executed as a separate thread.

For example, create a class in /src/or/confucius called "HelloRunnable.java" like this:

 package org.confucius;  

public class HelloRunnable implements Runnable {

public void run() {
System.out.println("Hello Runnable World!");
}

}




Another way, is to extend the Thread class.

In /src/org/confucius create a class HelloThread.java, like this:

 package org.confucius;  

public class HelloThread extends Thread {
public void run(){
System.out.println("Hello Thread World!");
}
}



The advantage is that the Thread class provides a whole bunch of useful methods. These become immediately available to HelloThread.

The disadvantage is that HelloThread cannot extend any other class.
(In which case, it will have to use method #1 and implement Runnable instead of extending Thread).

Let us write a class to create and execute these threads.

In /src/or/confucius, create a class ThreadTester.java, like this:

 package org.confucius;  

public class ThreadTester {

public static void main(String[] args) {
// Runnable
Runnable helloRunnable = new HelloRunnable();
new Thread(helloRunnable).start();


// Thread
Thread helloThread = new HelloThread();
System.out.println("Hello Thread state before: " + helloThread.getState());
helloThread.start();
System.out.println("Hello Thread state after: " + helloThread.getState());


}

}



Notice that we use the Thread.start() method to run the threads in both cases.
Notice that the HelloThread gives us some useful methods like getState().

To run this, right click on the ThreadTester.java file in Eclipse navigator, then select Run As -> Application.

If you look at the console, you might be surprised to see that the print statements are not in the order you expect! This is because your application is running 3 threads - the main application, the HelloRunnable thread and the HelloThread thread.

They print out at different times depending on how the JVM runs the threads.

Now for the next step - Executors.

Running threads using Thread.start() is OK for easy situations, but as the number of threads increase, you need some real thread management support.

Executors are classes which implement the Executor interface. They provide several thread management facilities like thread pooling, scheduling, termination, etc.

There are several Executors available. Let us try one of them.

In /src/org/confucius, create a class ExecutorTester.java, like this:

 package org.confucius;  

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ExecutorTester {

public static void main(String[] args) {
Runnable helloRunnable = new HelloRunnable();

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
executor.scheduleAtFixedRate(helloRunnable, 3, 2, TimeUnit.SECONDS);

try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}

executor.shutdownNow();
}
}



Here we are using the ScheduledThreadPoolExecutor. We are setting a thread pool size of 10 (this is the maximum number of threads that can be running at any given time).

We use the scheduleAtFixedRate() method to spawn and execute HelloRunnable every 2 seconds, starting at 3 seconds.

Finally we use shutDownNow() to terminate the thread after 10 seconds (10000 milliseconds).

Right click on the ThreadExecutor.java file in Eclipse navigator view, then select Run As --> Java Application.

You will see "Hello Runnable World!" printed in the console every 2 seconds.

No comments: