A concurrency problem can begin with an ordinary requirement: let two independent

operations make progress without forcing one to wait for the other. The requirement

is easy to state. Choosing among Thread, ExecutorService, Future,

CompletableFuture, locks, atomics, queues, and synchronizers is harder when they

look like competing answers to the same question.