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.
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:
System.out.println("Task not yet completed.");
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());
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
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
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()
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).
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.
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
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.