Java Reference
In-Depth Information
Chapter 6
Lambda Concurrency
The Java programming language is, at its core, a series of instructions. These instructions are executed in
sequence. By default, you only ever have one of these series going at a time. However, if you have multiple
processing cores on your machine, or if you have any kind of I/O, then this single series of instructions
suddenly becomes very inefficient. If your program has a lot to do, but its single stream has to wait for the
“read” I/O instruction to complete before doing anything else, then your program is wasting time. If you
have four processing cores, but only one stream of instructions, then you are at best only using a quarter of
your potential power. The solution to this is to have multiple streams of instructions executing at the same
time within your program, which is called concurrency.
If you have read anything about lambdas in Java 8, you've probably heard the words “lambda” and
“concurrency” used in the same breath. Concurrency seems to be one of the driving interests in adopting
lambdas, but exactly why lambdas help with concurrency is often left as an exercise to the reader. In this
chapter, we will see how and why lambdas play so nicely with concurrency. We are going to take a look at
the primary Java concurrency technologies, starting with the venerable Thread class and ultimately building
up to a highly concurrent system using streams. These streams are not the I/O streams: these are streams of
processing. What we will see is that lambdas make it easy to pass around instructions that can be executed
across multiple streams: while Java technically always had this capability, lambdas make the code readable,
and streams make implementing it easy.
It is easy for conversations about concurrency to wander off into the abstract, and even easier for
examples of concurrency to be trivially simple. To avoid this, we will use a consistent example throughout
this chapter, and simply solve this problem in different ways. (This practice of repeatedly solving a familiar
problem in different ways is called a code kata, a term coined by Dave Thomas.) In our case, the “problem
to solve” will be printing primes of increasing size: we will use Java's BigInteger class to generate primes
starting with 1 bit long and going up to 50,000 bits long. In order to make room for our concurrency, we will
say that the generated values do not need to be printed in order. The reference implementation is given in
Listing 6-1: in that listing, we generate the primes in a serial fashion.
Listing 6-1. Reference Implementation of Prime Generation
// PrimeFactory.java
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.*;
public class PrimeFactory {
/**
* Returns a number that has bit length {@code bitLength} and is
* probably prime. The odds of the value being prime are the same as
* {@link BigInteger#probablePrime(int, java.util.Random)}.
 
Search WWH ::




Custom Search