Java Reference
In-Depth Information
public ThreadPoolExecutor createThreadPoolExecutor() {
int processorCount = Math.max(1,
int corePoolSize = processorCount;
int maxPoolSize = processorCount * 2 + 1;
long threadTimeoutMag = 1L;
TimeUnit threadTimeoutUnit = TimeUnit.SECONDS;
BlockingQueue<Runnable> queue =
new ArrayBlockingQueue<>(processorCount * 4 + 1);
ThreadFactory threadFactory = createThreadFactory();
"thread factory for thread pool executor");
RejectedExecutionHandler rejectHandler = createdRejectedExecutionHandler();
"rejected execution handler for thread pool executor");
return new ThreadPoolExecutor(
threadTimeoutMag, threadTimeoutUnit,
Lambdas and Fork/Join
When we last left our bitlength prime generator, we had gotten a significant performance improvement by
leveraging Java's executors. However, this took a lot of set-up and noise. Wouldn't it be nicer if you could
just specify the work that you wanted to do, and not have to worry about the concurrency details? The good
news is that you can, using Java's Fork/Join pools. In Java 7, that functionality existed in the SDK. In Java 8,
lambdas make that functionality user friendly.
The basic concept of the Fork/Join pool is that you work on tasks that can fork additional work, and then
can join that work back into the main thread. You can create and manage the underlying thread pool if you
really care by using the ForkJoinPool class. However, you can also ignore the pool management entirely:
you can simply provide the work to perform concurrently, fire off that work, and join that work back into
your thread at some later point. It is really that simple: Java handles the rest.
Of course, there are a lot of caveats to the kind of work that you should pass into the Fork/Join
framework: long-blocking work, for instance, requires some careful handling. You can read about these
details in the JavaDoc for the ForkJoinTask and ForkJoinPool classes. However, for the kind of work that we
are dealing with, it is absolutely perfect.
What is even better is that the Fork/Join framework works extremely nicely with streams: you can
fork the work at one stage of the stream and join it in another. To implement our solution, we will define a
parallel stream of numbers, ranging from 1 to our maximum bitlength. We will then map our parallel stream
into a parallel stream of forked ForkJoinTask instances, each of which is generating a prime. Then we will
join those tasks back (handling the errors), and then print the result to standard out. This code is given in
Listing 6-5.
Search WWH ::

Custom Search