java left logo
java middle logo
java right logo
 

Home arrow Java SE Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 3942
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Pooling threads to execute short tasks E-mail
User Rating: / 65
PoorBest 

This Tech Tip reprinted with permission by java.sun.com

If you develop programs that execute many short-lived tasks, it's wise to take advantage of a technique called thread pooling. Instead of creating a thread for each new task and discarding the thread when the task is done, you can create a pool of threads and give the pool each task to execute. If a thread in the pool is available, the task executes immediately. The thread returns to the pool when the task is done. Otherwise, the task waits for a thread to become available from the pool before executing.

J2SE 5.0 offers a new java.util.concurrent package, and in that package there are concurrency utilities that provide a pre-built thread pooling framework. The Executor interface in java.util.concurrent provides a single method, execute, that accepts a Runnable object as follows:

   public interface Executor {
     public void execute(Runnable command);
   }

To use the thread pooling framework, you create an Executor instance, then you pass it some runnable tasks:

   Executor executor = ...;
   executor.execute(aRunnable1);
   executor.execute(aRunnable2);

Then you create or find an implementation of the Executor interface. The implementation could run the task immediately, in a new thread, or serially. For example, here is an implementation that spawns a new thread for each task:

   class MyExecutor implements Executor {
       public void execute(Runnable r) {
           new Thread(r).start();
       }
   }

The concurrency utilities also include a ThreadPoolExecutor class that offers support for many common pooling operations. With one of the four ThreadPoolExecutor constructors, you can specify options such as pool size, keep alive time, a thread factory, and a handler for rejected threads:

   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue)

   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue,
                             ThreadFactory threadFactory)

   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue,
                             RejectedExecutionHandler handler)

   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue,
                             ThreadFactory threadFactory,
                             RejectedExecutionHandler handler)

But you really don't need to call a constructor. Instead, the Executors class of the java.util.concurrent package creates the thread pool for you. In the simplest case, you call the newFixedThreadPool method in the Executors class and pass in the number of threads you want in the pool. You then use ExecutorService, an interface that extends Executor, to either execute Runnable tasks or submit them. Calling the submit method of ExecutorService allows you to get a result back. The submit method also returns a Future object that you can use to check if the task is done.

Let's run a test program to demonstrate the use of thread pools. First, here's a program, NamePrinter, that notifies you when it starts, pauses for some amount of time, and then notifies you when it's done.

   public class NamePrinter implements Runnable {
     private final String name;
     private final int delay;
     public NamePrinter(String name, int delay) {
       this.name = name;
       this.delay = delay;
     }
     public void run() {
       System.out.println("Starting: " + name);
       try {
         Thread.sleep(delay);
       catch (InterruptedException ignored) {
       }
       System.out.println("Done with: " + name);
     }
   }

Here is the test program, UsePool. It creates a thread pool of size 3, and adds 10 tasks to it (that is, 10 runs of NamePrinter). The UsePool program then waits for the tasks to finish before calling shutdown and awaitTermination. An ExecutorService should be shutdown before being terminated. There is also a shutdownNow method which attempts an immediate shutdown. Termination here is even faster than through the shutdown method. The shutdownNow method returns a List of any remaining Runnable tasks.

   import java.util.concurrent.*;
   import java.util.Random;
   
   
   public class UsePool {
     public static void main(String args[]) {
       Random random = new Random();
       ExecutorService executor = 
               Executors.newFixedThreadPool(3);
       // Sum up wait times to know when to shutdown
       int waitTime = 500;
       for (int i=0; i<10; i++) {
         String name = "NamePrinter " + i;
         int time = random.nextInt(1000);
         waitTime += time;
         Runnable runner = new NamePrinter(name, time);
         System.out.println("Adding: " + name + " / " + time);
         executor.execute(runner);
       }
       try {
         Thread.sleep(waitTime);
         executor.shutdown();
         executor.awaitTermination
                 (waitTime, TimeUnit.MILLISECONDS);
       catch (InterruptedException ignored) {
       }
       System.exit(0);
     }
    }

Compile NamePrinter and UsePool, then run UsePool. Here's a sample output run -- note that each run will be unique with the random sleeps present:

   Adding: NamePrinter 0 / 30
   Adding: NamePrinter 1 / 727
   Adding: NamePrinter 2 / 980
   Starting: NamePrinter 0
   Starting: NamePrinter 1
   Starting: NamePrinter 2
   Adding: NamePrinter 3 / 409
   Adding: NamePrinter 4 / 49
   Adding: NamePrinter 5 / 802
   Adding: NamePrinter 6 / 211
   Adding: NamePrinter 7 / 459
   Adding: NamePrinter 8 / 994
   Adding: NamePrinter 9 / 459   
   Done with: NamePrinter 0
   Starting: NamePrinter 3
   Done with: NamePrinter 3
   Starting: NamePrinter 4
   Done with: NamePrinter 4
   Starting: NamePrinter 5
   Done with: NamePrinter 1
   Starting: NamePrinter 6
   Done with: NamePrinter 6
   Starting: NamePrinter 7
   Done with: NamePrinter 2
   Starting: NamePrinter 8
   Done with: NamePrinter 5
   Starting: NamePrinter 9
   Done with: NamePrinter 7
   Done with: NamePrinter 9
   Done with: NamePrinter 8

Notice that the first three NamePrinter objects started quickly. Later NamePrinter objects started as each executing NamePrinter object finished.

There is much more to the thread pooling framework available in J2SE 5.0. For example, you can create scheduled thread pools, where you can schedule tasks to run "later".

For more information on thread pooling and the new concurrency utilities, see Concurrency Utilities.

Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.


 Related Tips

 

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.