Writing concurrent programs that can run in multiple threads and on multiple cores is crucial but daunting. Futures provides a convenient abstraction for many problem domains. The online course "Intermediate Scala" includes an up-to-date discussion of futures and the parts of java.util.concurrent that underlie the Scala futures implementation. Unlike Java's futures, Scala futures supports composition, transformations and sophisticated callbacks.
The author is managing editor of http://scalacourses.com, which offers self-paced online courses that teach Introductory and Intermediate Scala and Play Framework.
4. About Mike Slinn
• Principal at Micronautics Research
• Hands-on architect, mentor, trainer
• Interim technical leader for companies in
transition
• Recognized in US Federal court as a
software expert
• Author of Composable Futures with Akka 2.0
• Interested in artificial personality
• Coordinator of BASE and Scala for Startups
8. Standard Thread Pools
• Cached
• Fixed
• Scheduled
• Single
• Single scheduled
• Fork / join (JDK 7 and improved jsr166y)
• Variants with/without daemon threads often
required
9. Concurrency Definitions
• Concurrent tasks are stateful, often with
complex interactions
• Parallelizable tasks are stateless, do not
interact, and are composable
10. java.util.concurrent
• Akka is built on top of
java.util.concurrent (j.u.c.)
• Futures are designed to be used with a
Callable, which returns a result
• Executors contain factories and utility
methods for concurrent classes
• ExecutorService.shutdown()
12. j.u.c. Is Too Hard To Use
• Multithreaded programs tend to be buggy
o Non-determinism caused by concurrent threads
accessing (shared) mutable state.
• Actors and transactions manage state and
are therefore not the first solution you should
consider.
• To get deterministic processing, avoid
(shared) mutable state.
13. Concurrency Hazards
• CPU registers
• L1, L2 and L3 caches
o L1 cache for each core
o L2 cache shared by pairs of cores
o L3 cache shared by all cores
• Processors are different, so a program may
run fine on one system but fail on another
16. MESI Protocol
• Each processor cache can be in one of four
states:
o Modified
o Exclusive
o Shared
o Invalid
• When one core writes to main memory, the
entire cache block is marked invalid
• Block sizes depend on processor (64 bytes,
128 bytes, etc.)
17. Cache Line Ping-Pong
• Manifests even when external state is not
shared
o One or more cores repeatedly invalidate caches of
the other cores, even while accessing isolated state.
o The other cores must read data from main memory
instead of their local cache
o Slows program up to two orders of magnitude.
18. Cache Line Ping-Pong
1.j.u.c. solution:
@volatile var data = Array(threadCount)
synchronized(data) {
data(i) = whatever
}
2.Do not access external mutable state from a
thread
3. Use functional programming techniques
19. Large, Realtime Guidelines by Prismatic
• Use functional programming to build fine-
grained, flexible abstractions.
• Compose these abstractions to express
problem-specific logic.
• Prefer lightweight, composable custom
abstractions rather than monolithic
frameworks (e.g., Hadoop).
21. Better Concurrency Options
• Ordered by increasing complexity & overhead
o j.u.c.
o Scala parallel collections
o Akka futures* (Java & Scala)
o Akka/Scala dataflow*
o Akka actors (Java & Scala)
• You can mix & match the above
* Covered in my book:
“Composable Futures with Akka 2.0”
Covered in my April 23 InfoQ article.
22. Scala Parallel Collections
• Very easy to use
• Not configurable
• Block
• Composable
• Easy to reason with
• Benefits from ongoing improvements to
ForkJoinPool
o (Scala uses jsr166y)
25. Akka/Scala Dataflow*
• Callable from Scala only
• Has peculiar operators
• Easy to reason with
• Designed for shared mutable state
• Dataflow blocks are composable
• Good for coordination of asynchronous
activities
• Good for consolidating multiple sources of
data
26. Akka Actors
• Callable from Java & Scala
• Over-hyped (remember EJB 2?)
• Most complex option
• Distributed concurrency: can scale beyond
one motherboard
• Not composable
• Can be difficult or impossible to prove correct
• This should be your last option to consider
27. Akka Futures
• Callable from Java & Scala
• More flexible than Scala parallel collections
• Much less complex than Akka actors
• Composable
• Easy to reason with
• Payloads (Callables) should not have side
effects
• Should not be used with shared mutable
state
28. What is a Future?
• Holder for a result that will become available
at a later time.
• Each future is backed by a thread.
• If the computation fails, the future can also
hold the resulting Throwable.
• Write-once (immutable)
• Akka and Twitter futures are composable and
transformable (j.u.c. futures are not)
29. Akka & Twitter Futures
• Manage concurrency
• Higher-level than j.u.c. primitives
• Immutable
• Inexpensive
• Can be preset to a value or exception when
created.
• Blocking and non-blocking operations
supported
30. Composable Futures
• Operations on a future or a collection of
futures can be chained together without
blocking
• Transformations such as map and flatMap
can be applied to a single future
• Collections of futures can be manipulated
34. Statistical Nature
Large standard deviation; values are not tightly clustered around the
median; results vary a lot each time a measurement is taken.
Small standard deviation; values are tightly clustered around the median;
results do not vary much each time a measurement is taken.
36. Configure Thread Pools at Deployment
• Number and type of processors and other
hardware affects behavior
• Interaction with other thread pools
• Akka supports configuration files and
configuration strings for setting up thread
pools
38. flatMap Demo
• Combination of Future.map() and
List.flatten()
• Walks through a list and generates a second
list by flattening each item in the first list
• Will not evaluate the passed-in functor if the
future failed
• This demo implements the pseudo-code that
Marius Eriksen of Twitter showed for
flatMap last week at the Bay Area Scala
Enthusiasts meetup
39. flatMap Demo
1.Look up a token; return the user ID if
successful, otherwise fail.
2. Use the user ID to obtain a user information
if step 1 did not fail.
40. Code Summary
val userF: Future[User] =
Future(authenticate(token))
flatMap(id => getUser(id))
userF onComplete {
case Right(value: User) =>
println(value)
case Left(exception) =>
println(exception.getMessage)
}