In Chapter 13, Concurrency, we introduced concurrency and some of the building blocks that are available when programming in a multithreaded environment. However, writing concurrent programs using these so-called concurrency primitives is still problematic.
Most concurrent functions are blocking—for example, Thread.sleep. These are easy to understand and follow because code that uses them can be written imperatively (step by step). The drawback is that they are inefficient because any thread that invokes them will be blocked until the function returns. And, since threads have some overhead associated with them (memory and context switching), having too many blocked threads can be inefficient.
An alternative is the callback style, which we also demonstrated in Chapter 13, Concurrency. This style is more efficient, as threads do not need to be blocked. Instead...