Friday, June 4, 2010

Best waty to thread implementation in Java, Threads pools with the Executor Framework

Threads were the first approach in Java to support concurrency. The usage of the threads has the following disadvantages.

1. Creating a new thread causes some performance overhead
2. Too many threads can lead to reduced performance, as the CPU needs to switch between these threads.
3.You cannot easily control the number of threads, therefore you may run into out of memory errors due to too many threads.

The java.util.concurrent package offers improved support for concurrency compared to threads. The java.util.concurrent package helps solving several of the isues with threads.

Threads pools with the Executor Framework

Thread pools manage a pool of worker threads. The thread pools contains a work queue which holds tasks waiting to get executed. A thread pool can be described as a collection of runnables (work queue) and a connections of running threads. These threads are constantly running and are checking the work query for new work. If there is new work to be done they execute this Runnable. The Thread class itself provides a method, e.g. execute (Runnable r) to add runnables to the work queue.

The Executor framework provides example implementation of the java.util.concurrent.Executor interface, e.g. Executors.newFixedThreadPool(int n) which will create n worker threads. The ExecutorService adds lifecycle methods to the Executor, which allows to shutdown the Executor and to wait for termination.

If you want to use one thread pool with one thread which executes several runnables you can use Executors.newSingleThreadExecutor();

Create two java files:

MyRunnable.java

package com.suman;

/**
* @author Binod Suman
*/
public class MyRunnable implements Runnable {
private final String sql;

MyRunnable(String sql) {this.sql = sql;}

@Override
public void run() {
long sum = 0;
for (long i = 1; i < 5; i++) {
System.out.println(sql);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

App.java

package com.suman;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class App
{
private static final int noOfThreadInPool = 10;
public static void main( String[] args )
{
ExecutorService executor = Executors.newFixedThreadPool(noOfThreadInPool);
String sql="sql";
List> list = new ArrayList>();
for (int i = 1; i <=5; i++) {
if(i==1)sql="FIRST";
if(i==2)sql="SECOND";
if(i==3)sql="THIRD";
if(i==4)sql="FOURTH";
if(i==5)sql="FIFTH";

Runnable worker = new MyRunnable(sql);
executor.execute(worker);
}

// This will make the executor accept no new threads
// and finish all existing threads in the queue

executor.shutdown(); // Very Important

// Wait until all threads are finish

while (!executor.isTerminated()) {}

System.out.println("Finished all threads");
}
}


The main benefit of Executors Framework that you no need to manage thread yourself. Here you can give how many thread maximum do you want to generate in threadpool.

private static final int noOfThreadInPool= 10;
ExecutorService executor = Executors.newFixedThreadPoolnoOfThreadInPool

If you give noOfThreadInPool=5 then it will only create 5 thread to threadpool and you request for 6th thread to call executor.execute(worker); then it has to finish until one thread will free.

How you will use this in your project.

Suppose if you have one fixed work that you have to execute 10 times then make that method inside the MyRunnbale.java and put that method in run() method and call

Runnable worker = new MyRunnable(sql);
executor.execute(worker);

10 times.

But you can not return any value from MyRunnable class as run() method return type is void.

In case you expect your threads to return a computed result you can use java.util.concurrent.Callable. Callables allow to return values after competition. Callable uses generic to define the type of object which is returned.
If you submit a callable to an executor the framework returns a java.util.concurrent.Future. This futures can be used to check the status of a callable and to retrieve the result from the callable.

On the executor you can use the method submit to submit a Callable and to get a future. To retrieve the result of the future use the get() method.

Future and Collable Example
Create one more java file

MyCallable.java

package com.suman;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

/**
* @author Binod Suman
*/

public class MyCallable implements Callable {
private final String sql;

MyCallable(String sql) {this.sql = sql;}

@Override
public List call() throws Exception {
long sum = 0;
List list = new ArrayList();
for (long i = 1; i < 6; i++) {
System.out.println(sql);
list.add(sql+i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return list;
}
}


And do some change in App.java

package com.suman;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class App
{
private static final int noOfThreadInThreadPool = 10;

public static void main( String[] args )
{
ExecutorService executor = Executors.newFixedThreadPool(noOfThreadInThreadPool);
String sql="sql";
List> list = new ArrayList>();
for (int i = 1; i <=5; i++) {
if(i==1)sql="FIRST";
if(i==2)sql="SECOND";
if(i==3)sql="THIRD";
if(i==4)sql="FOURTH";
if(i==5)sql="FIFTH";

// Runnable worker = new MyRunnable(sql);
// executor.execute(worker);

Callable worker = new MyCallable(sql);
Future submit = executor.submit(worker);
list.add(submit);
}


// To see the result
for (Future future : list) {
try {
List list2 = future.get();
System.out.println("ALL LIST:: "+list2);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}

}



// This will make the executor accept no new threads
// and finish all existing threads in the queue
executor.shutdown();
// Wait until all threads are finish
while (!executor.isTerminated()) {}

System.out.println("Finished all threads");
}
}

I think, it is best way to use the thread. Your suggestions or question is always most welcom. :)

Thanks ........... :)

source: http://www.vogella.de/articles/JavaConcurrency/article.html#threadpools





1 comment: