Thursday, August 30, 2007

10,000 Threads Are Better Than One

example source code, overview
In this post we will be following the business logic for using multi-threading and concurrency as we explore the expansion of the availability service from its basic form to one extended for more practical application presented in the previous posting.

[basic availability service] an application that communicated with business systems (enterprise resource planning - inventory management in particular) to read current stock information, including current demand allocations; compare to new single demand; ultimately, displaying lead time to fulfill customer requirement whether from stock, assembling from stocked components on a bill of material, or purchasing/fabricating item through the portions if not all of its cumulative lead time...

Since the business world does not exist in a parallel universe where customer demand and actual supply are always in constant harmony, the basic implementation for availability above is insufficient as a final answer to a demand requirement that has differing priorities (e.i. fulfill two or more needs at once). To clarify, please re-read the following excerpt:

[extended availability service] As a customer, you may have an immediate need for five light bulbs or else you will be in darkness for the entire day, but you get cost efficiencies purchasing light bulbs in quantities of 1,000. The purpose of this extension to the availability service is to allow you as the customer understand that you can get 50 from stock today...

The first need of concern is to restore service: get the lights on! The second priority is to ensure that the effort to restore service is done in a fashion that positively impacts the bottom-line long term as well as lessen the likelihood of future outage. At its most basic sense, the response to the above variation in need could involve two calls to availability code: one returning lead time of quantity acquirable through stock (e.g. same day); the other, time through procurement/manufacturing processes (e.g. 60 days).

However, if you add usage and more complex items an scenarios to your thought process over my simple light bulb shortage, the application requirement slowly becomes (or at least it did in my case) one that asks the question "what is the individual lead time of each quantity of the total 1,000 light bulbs requested?"


An Array of Threads
Following the thought above, to answer the question, a user of the availability tool would run sequential requests with required quantities from 1 - 1,000. The first step is to change the process of making the requests an automated one versus having to make 1,000 separate requests. The user would like to query the system once and get 1,000 responses. With the potential for thousands or tens of thousands, the first logical conclusion I got was "10,000 threads are better than one."

The example thread AThread does a simple wait(x milliseconds) to simulate some processing time, but can easily be modified to be a synchronized (depending on locking requirements) block of code executing logic necessary to determine a specific item and required quantity availability. For example:


...

/* call() method for AThread.java
* @see java.util.concurrent.Callable#call()
*/
public Object call() throws Exception {
// Define your own result object and availability processor
LeadTimeResultObject ltro = new LeadTimeResultObject();
AvailabilityProcessor process = new AvailabilityProcessor();
// Use synchronized blocks for thread safety
synchronized(this){
// Insert application logic to get lead time
ltro = process.getLeadTimeResult("some item id", "some quantity");
}
return ltro;
}

...

The ArrayOfThreads class illustrates how to implement calling the lead time availability code through use of an AThread array.

AThread calculators[] = new AThread[100];

Using a for loop to iterate from 0 to 99 index of array, you can use the Constructor of the AThread object to pass in data needed to make each thread calculation unique (e.g. item id and quantity equal to 1 to 100 - array index + 1). Although this accomplishes the first task of automating the requests, each thread must complete serially making the net result of the application performance exactly that of having the main thread executing one availability process 100 times (see output example 1: processing times go in sequence and so total processing time is long).

In addition, this will most likely crash your application and/or back-end systems as user quantity requirements scale upward.

I know this is not very practical for the use case we are exploring, but another component of the application I wrote was used to keep statistics on requests for availability. These statistics were needed for later analysis and did not need to be sent back to user. Applying the methodology of thread arrays for background processing that needs to be done at some point is a perfect fit. User leaves the site or at least is satisfied by a response, while additional business logic is applied as more data is gathered and stored in a business intelligence/reporting back-end.

Thread pooling or utilizing all the threads simultaneously would answer both the automation of user process and most efficient run time concerns. See next post in the concurrent threading series for a detail on the ArrayOfThreadsPooled object included in the source code available for download above.

No comments: