Home > Articles > Programming > Java

  • Print
  • + Share This
From the author of

Conclusions

As you can see, a thread pool is a useful way to limit the amount of threads that a Java program will be using. This article presented a complete thread pool that can be used with Java. This thread pool can easily become the starting point for any application that you create, which requires a thread pool.

Listing 1—The ThreadPool Class

package com.heaton.threads;
import java.util.*;

/**
 * Java Thread Pool
 * 
 * This is a thread pool that for Java, it is
 * simple to use and gets the job done. This program and
 * all supporting files are distributed under the Limited
 * GNU Public License (LGPL, http://www.gnu.org).
 * 
 * This is the main class for the thread pool. You should
 * create an instance of this class and assign tasks to it.
 * 
 * For more information visit http://www.jeffheaton.com.
 * 
 * @author Jeff Heaton (http://www.jeffheaton.com)
 * @version 1.0
 */
public class ThreadPool {
 /**
  * The threads in the pool.
  */
 protected Thread threads[] = null;
 /**
  * The backlog of assignments, which are waiting
  * for the thread pool.
  */
 Collection assignments = new ArrayList(3);
 /**
  * A Done object that is used to track when the
  * thread pool is done, that is has no more work
  * to perform.
  */
 protected Done done = new Done();

 /**
  * The constructor.
  * 
  * @param size  How many threads in the thread pool.
  */
 public ThreadPool(int size)
 {
  threads = new WorkerThread[size];
  for (int i=0;i<threads.length;i++) {
   threads[i] = new WorkerThread(this);
   threads[i].start();
  }
 }

 /**
  * Add a task to the thread pool. Any class
  * which implements the Runnable interface
  * may be assienged. When this task runs, its
  * run method will be called.
  * 
  * @param r   An object that implements the Runnable interface
  */
 public synchronized void assign(Runnable r)
 {
  done.workerBegin();
  assignments.add(r);
  notify();
 }

 /**
  * Get a new work assignment.
  * 
  * @return A new assignment
  */
 public synchronized Runnable getAssignment()
 {
  try {
   while ( !assignments.iterator().hasNext() )
    wait();

   Runnable r = (Runnable)assignments.iterator().next();
   assignments.remove(r);
   return r;
  } catch (InterruptedException e) {
   done.workerEnd();
   return null;
  }
 }

 /**
  * Called to block the current thread until
  * the thread pool has no more work.
  */
 public void complete()
 {
  done.waitBegin();
  done.waitDone();
 }


 protected void finalize()  
 {
  done.reset();
  for (int i=0;i<threads.length;i++) {
   threads[i].interrupt();
   done.workerBegin();
   threads[i].destroy();
  }
  done.waitDone();
 }
}

/**
 * The worker threads that make up the thread pool.
 * 
 * @author Jeff Heaton
 * @version 1.0
 */
class WorkerThread extends Thread {
 /**
  * True if this thread is currently processing.
  */
 public boolean busy;
 /**
  * The thread pool that this object belongs to.
  */
 public ThreadPool owner;

 /**
  * The constructor.
  * 
  * @param o the thread pool 
  */
 WorkerThread(ThreadPool o)
 {
  owner = o;
 }

 /**
  * Scan for and execute tasks.
  */
 public void run()
 {
  Runnable target = null;

  do {
   target = owner.getAssignment();
   if (target!=null) {
    target.run();      
    owner.done.workerEnd();
   }
  } while (target!=null);
 }
}

Listing 2—The Done Class

package com.heaton.threads;

/**
 * 
 * This is a thread pool for Java, it is
 * simple to use and gets the job done. This program and
 * all supporting files are distributed under the Limited
 * GNU Public License (LGPL, http://www.gnu.org).
 * 
 * This is a very simple object that
 * allows the TheadPool to determine when 
 * it is done. This object implements
 * a simple lock that the ThreadPool class
 * can wait on to determine completion.
 * Done is defined as the ThreadPool having
 * no more work to complete.
 * 
 * Copyright 2001 by Jeff Heaton
 *
 * @author Jeff Heaton (http://www.jeffheaton.com)
 * @version 1.0
 */
public class Done {

 /**
  * The number of Worker object
  * threads that are currently working
  * on something.
  */
 private int _activeThreads = 0;

 /**
  * This boolean keeps track of if
  * the very first thread has started
  * or not. This prevents this object
  * from falsely reporting that the ThreadPool 
  * is done, just because the first thread
  * has not yet started.
  */
 private boolean _started = false;
 /**
  * This method can be called to block
  * the current thread until the ThreadPool
  * is done.
  */

 synchronized public void waitDone()
 {
  try {
   while ( _activeThreads>0 ) {
    wait();
   }
  } catch ( InterruptedException e ) {
  }
 }
 /**
  * Called to wait for the first thread to 
  * start. Once this method returns the
  * process has begun.
  */

 synchronized public void waitBegin()
 {
  try {
   while ( !_started ) {
    wait();
   }
  } catch ( InterruptedException e ) {
  }
 }


 /**
  * Called by a Worker object
  * to indicate that it has begun 
  * working on a workload.
  */
 synchronized public void workerBegin()
 {
  _activeThreads++;
  _started = true;
  notify();
 }

 /**
  * Called by a Worker object to 
  * indicate that it has completed a 
  * workload.
  */
 synchronized public void workerEnd()
 {
  _activeThreads--;
  notify();
 }

 /**
  * Called to reset this object to
  * its initial state.
  */
 synchronized public void reset()
 {
  _activeThreads = 0;
 }

}

Listing 3—The Example Worker Thread

import com.heaton.threads.*;

/**
 * This class shows an example worker thread that can
 * be used with the thread pool. It demonstrates the main
 * points that should be included in any worker thread. Use
 * this as a starting point for your own threads.
 * 
 * @author Jeff Heaton (http://www.jeffheaton.com)
 * @version 1.0
 */
public class TestWorkerThread implements Runnable {
 static private int count = 0;
 private int taskNumber;
 protected Done done;

 /**
  * 
  * @param done
  */
 TestWorkerThread()
 {
  count++;
  taskNumber = count;
 }

 public void run()
 {
  for (int i=0;i<100;i+=2) {
   System.out.println("Task number: " + taskNumber + 
             ",percent complete = " + i );
   try {
    Thread.sleep((int)(Math.random()*500));
   } catch (InterruptedException e) {
   }
  }
 }
}

Listing 4—The ThreadPool Class

import com.heaton.threads.*;

/**
 * Main class used to test the thread pool.
 * 
 * @author Jeff Heaton (http://www.jeffheaton.com)
 * @version 1.0
 */
public class TestThreadPool {
 /**
  * Main entry point.
  * 
  * @param args  No arguments are used.
  */
 public static void main(String args[])
 {
  ThreadPool pool = new ThreadPool(10);

  for (int i=1;i<25;i++) {
   pool.assign(new TestWorkerThread());
  }

  pool.complete();

  System.out.println("All tasks are done.");
 }
}
  • + Share This
  • 🔖 Save To Your Account