Google

Mar 27, 2012

Java 5 Executor Framework - why use thread pools?

Q. What is a thread pool, and how will you create them in Java? Why do you need an Executor framework?
A. A thread pool consists of a collection of worker threads. A work queue is optional though most of the advanced implementations have a configurable work queue. The threads in the pool constantly run and  check the work queue for new work. If there is new work to be done they execute this Runnable.

In Java 5, Executor framework was introduced with the java.util.concurrent.Executor interface. This was introduced to fix some of the shortcomings discussed below.

1. The Executor framework is a framework for standardizing invocation, scheduling, execution, and control of asynchronous tasks according to a set of execution policies.


2. Even though the threads are light-weighted than creating a process, creating them utilizes a lot of resources. Also, creating a new thread for each task will consume more stack memory as each thread will have its own stack and also the CPU will spend more time in context switching. Creating a lot many threads with no bounds to the maximum threshold can cause application to run out of heap memory. So, creating a ThreadPool is a better solution as a finite number of threads can be pooled and reused. The runnable or callable tasks will be placed in a queue, and the finite number of threads in the pool will take turns to process the tasks in the queue.


Here is the sample code:



import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Sum  implements Runnable {
 
    private static final int NO_OF_THREADS= 3;
 
    int maxNumber;
 
    public Sum(int maxNumber) {
       this.maxNumber = maxNumber;
    }
 
    /** method where the thread execution will start **/
    public void run(){
        int sum = 0;
        for (int i = 0; i = maxNumber; i++) {
           sum += maxNumber;
        } 
        
        System.out.println("Thread " + Thread.currentThread().getName() + " count is " + sum);
    }
    
    
    /** main thread. Always there by default. **/
    public static void main(String[] args) {
       ExecutorService executor = Executors.newFixedThreadPool(NO_OF_THREADS);   // create a pool of 3 threads
       for (int i = 10000; i < 10100; i++) {
          Runnable worker = new Sum(i);               // create worker threads
          executor.execute(worker);                   // add runnables to the work queue 
       }
  
       // This will make the executor accept no new threads
       // and finish all existing threads in the queue
       executor.shutdown();
  
       // Wait until all threads have completed
       while (!executor.isTerminated()) {

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

}

3. The Runnable interface's void run( ) method has no way of returning any result back to the main thread. The executor framework introduced the Callable interface that returns a value from its call( ) method. This means the asynchronous task will be able to return a value once it is done executing.

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 Sum  implements Callable<String> {
 
 private static final int NO_OF_THREADS = 3;
 
 int maxNumber;
 
 public Sum(int maxNumber) {
    this.maxNumber = maxNumber;
 }
 
  /** method where the thread execution will start
    *  this can return a value
    */
    public String call(){
        int sum = 0;
        for (int i = 0; i <= maxNumber; i++) {
            sum += maxNumber;
        } 
        
        return Thread.currentThread().getName() + " count is " + sum;
    }
    
    
    /** main thread. Alwyas there by default. **/
    public static void main(String[] args) {
      ExecutorService executor = Executors.newFixedThreadPool(NO_OF_THREADS);                       // create a pool of 3 threads
      List<Future<String>> list = new ArrayList<Future<String>>(10);  // provides facility to return results asynchronously
     
      for (int i = 10000; i < 10100; i++) {
        Callable<String> worker = new Sum(i);                 // create worker threads 
        Future<String> submit = executor.submit(worker);      // add callables to the work queue
        list.add(submit);                                            // provides facility to return results asynchronously
      }
  
      //process the results asynchronously when each thread completes its task
      for (Future<String> future : list) {
        try {
            System.out.println("Thread " + future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
           e.printStackTrace();
        }
      }
  
  
      executor.shutdown();
  
      System.out.println("Finished all threads");
   }

}

The output is something like

Thread pool-1-thread-1 count is 100010000
Thread pool-1-thread-2 count is 100030002
Thread pool-1-thread-3 count is 100050006
Thread pool-1-thread-1 count is 100070012
Thread pool-1-thread-1 count is 100090020
...

4. The various Executor implementations provide different execution policies to be set while executing the tasks. For example, the ThreadPool supports the following policies:

  • newFixedThreadPool: Creates threads as tasks are submitted, up to the maximum pool size, and then attempts to keep the pool size constant.
  • newCachedThreadPool: Can add new threads when demand increases, no bounds on the size of the pool.
  • newSingleThreadExecutor: Single worker thread to process tasks, Guarantees order of execution based on the queue policy (FIFO, LIFO, priority order).
  • newScheduledThreadPool: Fixed-size, supports delayed and periodic task execution.
5. The ExecutorService provides facilities to shut down an application gracefully, abruptly, or somewhere in-between.

Q. What design pattern does the executor framework use?
A. The Executor is based on the producer-consumer design pattern, where threads that submit tasks are producers and the threads that execute tasks are consumers. In the above examples, the main thread is the producer as it loops through and submits tasks to the worker threads. The "Sum" (i.e. a worker thread) is the consumer that executes the tasks submitted by the main (i.e. consumer) thread. Check this blog to learn  more detailed explanation on the producer-consumer design pattern.


Labels:

39 Comments:

Anonymous Anonymous said...

Amazing article. I desire you up-to-date your blog significantly more often, I just cannot seem to be to acquire adequate of your blog. I preserved your blog in my bookmarks. Would it be feasible to do a guest post sometime?…

7:42 AM, April 22, 2012  
Anonymous Anonymous said...

Good work.. keep it up

2:43 AM, May 11, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Thanks.

10:50 AM, May 11, 2012  
Anonymous Anonymous said...

thanks for this blogger..
I want to add one more question. Like what design pattern used in executor frame work?
Ans: Produces Consumer design pattern

Very nice effort by you. Please keep it up ..

5:20 AM, May 17, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Good point. I have updated it. Thanks for the feedback.

10:18 AM, May 17, 2012  
Anonymous Anonymous said...

Great stuff!

11:54 AM, May 26, 2012  
Blogger sumit said...

I did not understand most of the stuff :(

12:04 PM, June 29, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Do the rest of the multi-threading before you go to thread pools with the executor framework.

Alternatively, if you post any specific doubts, one of the followers/readers or I can try and clarify it for you. This will also help me improve the post.

12:29 PM, June 29, 2012  
Blogger laxman said...

very good work

4:13 PM, July 03, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Thanks Laxman.

4:18 PM, July 03, 2012  
Blogger Monstercourses said...

Thanks for your wonderful information which helped us to join java online training

2:58 AM, July 19, 2012  
Blogger KAVIRAJ said...

Great stuffs!!!

3:22 AM, September 19, 2012  
Blogger shishir sarkar said...

Thanks for good posting on Thread pool

12:19 PM, September 28, 2012  
Anonymous Anonymous said...

Hi,

Is it safe to send JMS messages using the results of the thread completion.

//process the results asynchronously when each thread completes its task from

10:04 AM, October 03, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Not sure what you mean. Can you please clarify it a bit more?

12:05 PM, October 04, 2012  
Blogger Ram said...

Hi ,
Is it safe to use Executor framework within J2EE container?

Thanks
Ram

3:30 PM, October 23, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Spawning your own thread within a JEE container is discouraged because all resources within the environment are meant to be managed, and potentially monitored, by the server. There are ways to do this "correctly", but it is dependent on the platform being used. For example, The commonj WorkManager can be used for WebSphere and WebLogic JEE container as well as others

3:53 PM, October 23, 2012  
Anonymous Anonymous said...

Hi Blogger,I think this is good online tutorial for learning totally java related technologies for freshers as well as experience candidates...U doing good job.One small doubt regarding web services...what is the use of web services in real time projects can you post one good example.

Thanks

Chandu

3:29 AM, November 15, 2012  
Anonymous Anonymous said...

Good article. gave a good high level understanding of the executor framework. Can you please let me know what does spring use? I believe it uses the executor framework. Does the Executor framework used only for execution part? as in is it only a meeting point for a supplier and consumer OR does it handle the intricacies of thread handling?

3:45 AM, December 04, 2012  
Anonymous Anonymous said...

Good Article ...

11:50 PM, December 28, 2012  
Blogger Ashish said...

Very Nice work...really appriciated...

8:19 PM, January 08, 2013  
Blogger Felipe Alarcon Morales said...

Very good work. I need to send about 100,000 emails (no spam) html with attachment. You can do it with thread pool? Also need to know their status, is this possible?

Thanks in advance

5:47 AM, January 16, 2013  
Anonymous Rajasekhar said...

very nice article. good understanding on thread pools using concurrency package.

5:34 AM, January 19, 2013  
Anonymous Anonymous said...

Fantastic article... I am a newbie to multithreading / executors and was wondering what they were... This article is very good... thanks...

4:23 AM, February 25, 2013  
Blogger Sony Tiwary said...

perfect explanation.........

9:20 PM, September 12, 2013  
Anonymous Anil said...

good article .. thank you.

11:52 PM, September 21, 2013  
Anonymous Anonymous said...

Hello sir..very nice blog i have ever found.

10:43 PM, October 17, 2013  
Blogger puneet agarwal said...

Nice Article Appreciate your efforts !!!!

4:07 AM, November 11, 2013  
Blogger Jigyasa said...

very informative articles.... thanks.

4:06 AM, February 10, 2014  
Blogger Unknown said...

I stumbled on your blogs by chance and can't speak enough about how good , explanatory they are. You have done an amazing job in putting complex stuff in such a simple way. Thanks a lot and keep up the good work !

12:30 AM, February 28, 2014  
Blogger Santanu Nandi said...

Hi Arulkumaran,
Overall your explanation is good. But few places I see there are some fundamental mistake. If you please correct those places that it will be good for beginners.
The first line of this page says,"A thread pool is a collection of runnables with a work queue." I think that is not correct. Essentially a ThreadPool consists of a collection of Worker Thread. The work queue is optional. though most of the advanced implementations have a configurable work queue. But the point is a thread pool is definitely not "a collection of runnables".

6:15 AM, March 06, 2014  
Blogger Arulkumaran Kumaraswamipillai said...

Thanks Santhanu for your valuable feedback, and it has been fixed.

6:51 PM, March 08, 2014  
Blogger Amar Goud said...

Hi,
In sample code the thread pool size is fixed no i.e 3. I want to know is there any memory issues if i use thread pool size as 100. How can i decide thread pool size for avoiding memory issues.

Thanks,

Amar Goud

5:22 PM, April 15, 2014  
Blogger Arulkumaran Kumaraswamipillai said...

It depends on how may CPU cores your machine has. It is not recommended to have too many threads. There is cachedThreadPool as well that you can use instead of the fixed thread pool. You need to make this value configurable in a properties file, and also need to conduct performance testing to monitor CPU and memory usage.

5:52 PM, April 15, 2014  
Blogger Amar Goud said...

Hi Arulkumaran,
Is there any calculation to decide no of threads feasible for one CPU Core.

Thanks,
Amar Goud

9:50 PM, April 17, 2014  
Blogger Arulkumaran Kumaraswamipillai said...

No. That is why performance testing is important. You can get some guidance to start with using Amdahl's law.

11:08 PM, April 17, 2014  
Anonymous Anonymous said...

It is recommended to implement number of threads=number of processors+1

Ex:ExecutorService executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1);

5:22 PM, May 09, 2014  
Anonymous Anonymous said...

Simply Brilliant.

4:14 PM, September 10, 2014  
Anonymous Anonymous said...

Please correct the for loop in Runnable. Make it as below
for(int i =0; i <= maxNumber; i++)

instead of for (int i = 0; i = maxNumber; i++)

9:59 PM, September 11, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home