  In the past decades, many different programming models for managing
concurrency in applications have been proposed, such as the actor model,
Communicating Sequential Processes, and Software Transactional Memory. The
ubiquity of multi-core processors has made harnessing concurrency even more
important. We observe that modern languages, such as Scala, Clojure, or F#,
provide not one, but multiple concurrency models that help developers manage
concurrency. Large end-user applications are rarely built using just a single
concurrency model. Programmers need to manage a responsive UI, deal with file
or network I/O, asynchronous workflows, and shared resources. Different
concurrency models facilitate different requirements. This raises the issue of
how these concurrency models interact, and whether they are composable. After
all, combining different concurrency models may lead to subtle bugs or
inconsistencies.
  In this paper, we perform an in-depth study of the concurrency abstractions
provided by the Clojure language. We study all pairwise combinations of the
abstractions, noting which ones compose without issues, and which do not. We
make an attempt to abstract from the specifics of Clojure, identifying the
general properties of concurrency models that facilitate or hinder composition.
