RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Building Multithreaded Java Applications : Page 4

The Java concurrency utilities released in Java 5.0 simplified the development of multithreaded applications through their simple-to-use but robust and powerful API.


Creating a Thread Pool Executor

Creating a ThreadPoolExecutor is straightforward. You just need to call the CustomThreadPoolExecutor class constructor and pass the appropriate configuration parameters. The following code snippet creates a fixed-size thread pool by defining the same value for the number of core threads and the maximum number of threads:

private ThreadPoolExecutor executor;

public OrderProcessorMain() {
  // create a thread pool with fixed number of threads
  executor = new CustomThreadPoolExecutor(THREAD_POOL_SIZE,
      new LinkedBlockingQueue<Runnable>());


The timeout value of 0L makes sure the worker thread should not time out due to inactivity. The last argument is the blocking queue object for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.

Alternatively, you could create a fixed thread pool using the java.uti.concurrent.Executors utility class.

ExecutorService executorService = Executors.newFixedThreadPool(2);

This method implementation returns the ThreadPoolExecutor object with a fixed-core and max-pool thread size.

Creating and Submitting Tasks

After creating ThreadPoolExecutor, you need to create tasks for processing orders. You create these tasks using the OrderProcessorCallable class created in the previous section. The OrderProcessorCallable constructor takes a task name and an order queue object for retrieving the OrderVO object.

// create Callable task
OrderProcessorCallable callable1 = new OrderProcessorCallable(
      "OrderProcessor_1", orderVOQueue);

Remember that the call method of the OrderProcessorCallable class does not return until the running variable is true or the code throws an exception.

The next step is to store a reference to the callable object. This allows you can to call the setRunning method to update the running variable value and make the call method return gracefully. An advantage to this technique is you can call other methods to get object state information, such as the number of orders that have been processed at a certain point in time.

// store reference to callable object in collection
callableMap.put(callable1.getThreadName(), callable1);

The above code is useful because the Future object returned by the ExecutorService.submit method cannot be used for getting reference to the Callable object or for calling any method on the Callable object.

To execute the OrderProcessorCallable task, you call the submit method and pass a task reference. This method returns an object of type Future, which you can use for the following purposes:

  • Checking task status
  • Getting a result object returned by the Callable.call() method
  • Canceling the task
    // submit callable tasks
    Future<Integer> future;
    future = executor.submit(callable1);

The Future object is also stored in another collection for checking task status and retrieving the processing result. If you do not want to explicitly store Future objects in a collection, you can use the ExecutorCompletionService utility class. It provides a useful method for retrieving and removing completed tasks from its internal task queue.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date