Future and FutureTask
In earlier versions of Java, it is very difficult to find the status of an executing thread and make the thread return a value after execution. Because the run method returns void, you need to write a lot of code to get a return value from the thread. Programmers who tried this approach understand the ordeals associated with it.
Using the
Future interface or the FutureTask class you can get a return value from the asynchronous execution of the thread. The
Future interface provides methods to check if the computation is complete, retrieve the results of the computation, or cancel the computation. FutureTask provides the basic implementation of the
Future interface methods. The results can be retrieved only when the computations have completed; if the computation is not completed, the
get method will block.
The
MyStringReverser.java file demonstrates the use of the FutureTask class with an easy-to-understand example. It reverses the submitted string slowly at a rate of one char per second. In the mean time, the main thread keeps polling to see if the task is completed:
while(!future.isDone()){
System.out.println("Task not yet completed.");
try{
Thread.currentThread().sleep(500);
}catch(InterruptedException ie){
System.out.println("Will check after 1/2 sec."); }
}
After the task is completed, the result is retrieved from the Future object using the get method:
System.out.println("Here is result..."+future.get());
ThreadPoolExecutor
With the ThreadPoolExecutor class, you can write your own server. This class provides many features for configuring and tuning it, similar to many large-scale enterprise EJB servers. The following are a few of its configurable parameters:
- Core and maximum poolsizes
By setting
corePoolSize and
maximumPoolSize to the same value, you create a fixed-size thread pool. By setting
maximumPoolSize to an essentially unbounded value such as
Integer.MAX_VALUE, you allow the pool to accommodate an arbitrary number of concurrent tasks.
By default,
ThreadPoolExecutor initially creates and starts even core threads only when new tasks need them, but you can override this dynamically using
prestartCoreThread or
prestartAllCoreThreads.
If the pool currently has more than
corePoolSize threads, excess threads will be terminated if they have been idle for more than the
keepAliveTime.
Queuing follows the following rules:
- If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
- If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
- If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
This class provides
beforeExecute() and
afterExecute() hook methods that are called before and after execution of each task. In order to use them, you must sub-class the class (as these methods are protected).
MyThreadPoolExecutor.java provides detailed examples to monitor various configured parameters. You can uncomment the code to see for yourself how the pool and queue sizes vary with the addition and completion of each task. You also can play with the value settings in the code.
Concurrent Collections
JDK 1.5 provides the following Collection implementations that are designed for use in multithreaded contexts:
The ConcurrentHashMap class provides full thread-safe concurrency support for retrievals and adjustable expected concurrency for updates.
CopyOnWriteArraySet is a thread-safe variant of
set, and
CopyOnWriteArrayList is a thread-safe variant of
ArrayList. Each makes a copy of the underlying array or sets it before modifying the original. As a result, the reads are fast but the updates are slow.
Concurrent collection classes provide snapshot-style data to the
Iterators (even when the underlying data is changed, it is not reflected in the
Iterators).
Synchronizers
JDK 1.5 provides advanced classes like Semaphore, CountDownLatch, CyclicBarrier, and an Exchanger for special-purpose synchronization. A detailed analysis and usage of these classes is beyond the scope of this article, as it requires some academic background.
With this new set of classes, you can convince your thread-scared, technical boss to develop multithreaded applications.